mirror of
https://github.com/tj/git-extras.git
synced 2026-09-10 23:46:24 -04:00
Compare commits
531 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cf28ec559 | ||
|
|
09b77e8ed6 | ||
|
|
4c38988ba9 | ||
|
|
dbf68bac59 | ||
|
|
03569856db | ||
|
|
d11e45f0b1 | ||
|
|
fd2e03cf55 | ||
|
|
5a14757944 | ||
|
|
b450b36036 | ||
|
|
7f36d37283 | ||
|
|
184d37e980 | ||
|
|
e92878b81b | ||
|
|
b9e1d88f2c | ||
|
|
99207eee8e | ||
|
|
9d6319becb | ||
|
|
2bdeb59a73 | ||
|
|
c5a0fdf660 | ||
|
|
8d1c970031 | ||
|
|
c06fad59d2 | ||
|
|
65dd36ae62 | ||
|
|
967e339f91 | ||
|
|
ae3d30fb6e | ||
|
|
032090e847 | ||
|
|
5367101f2e | ||
|
|
6ed2643252 | ||
|
|
b9bd309a87 | ||
|
|
6f4cf0c1bb | ||
|
|
f5c48e4842 | ||
|
|
daf9d4148e | ||
|
|
eb34655aea | ||
|
|
1f1320f4d6 | ||
|
|
4d05955bc5 | ||
|
|
b57eb8b92a | ||
|
|
cf6d40d446 | ||
|
|
14586c7da0 | ||
|
|
5c9a7a2533 | ||
|
|
215382b12d | ||
|
|
13cbdfc51e | ||
|
|
3ddc315a76 | ||
|
|
c63b46a33b | ||
|
|
d4cd272556 | ||
|
|
783812b627 | ||
|
|
c49ca70814 | ||
|
|
18ecffef5e | ||
|
|
aadf5f874b | ||
|
|
18d1017325 | ||
|
|
a841845d9a | ||
|
|
8eed5f49ad | ||
|
|
64687599ae | ||
|
|
8ce63003c0 | ||
|
|
1a9b0c2ab4 | ||
|
|
82cc37d0f5 | ||
|
|
df53711fc7 | ||
|
|
e691826b4b | ||
|
|
fdaca2cd26 | ||
|
|
3db275cbe2 | ||
|
|
1345c5977d | ||
|
|
2f4b57d52b | ||
|
|
c23da8ae9c | ||
|
|
f1f50ac5ba | ||
|
|
0989b773de | ||
|
|
65203312c1 | ||
|
|
a2c424aada | ||
|
|
d291b2775c | ||
|
|
fb0bc6950b | ||
|
|
21a086c009 | ||
|
|
8eb1d72f07 | ||
|
|
233686d2a2 | ||
|
|
5c3fb1b062 | ||
|
|
5ca9360109 | ||
|
|
16d1445271 | ||
|
|
4d2d393142 | ||
|
|
ffee88a246 | ||
|
|
da03b7b133 | ||
|
|
f0671e2733 | ||
|
|
2c161aae02 | ||
|
|
f0b9e18e54 | ||
|
|
c32869de37 | ||
|
|
e1a4e7195d | ||
|
|
b766a655ce | ||
|
|
e34dea9b7a | ||
|
|
3bac05e690 | ||
|
|
a7ad306a6b | ||
|
|
dcb8bd6c54 | ||
|
|
a1bf09e8e0 | ||
|
|
615ea971cb | ||
|
|
e692b9619a | ||
|
|
a17d2fb15d | ||
|
|
52897f73b9 | ||
|
|
5f19424a50 | ||
|
|
b54d8c7c50 | ||
|
|
9049967232 | ||
|
|
cdbcef3227 | ||
|
|
a4b637346d | ||
|
|
1843afb38a | ||
|
|
28b48c7432 | ||
|
|
2c2bd07693 | ||
|
|
e39b1ab6a6 | ||
|
|
058cb0763e | ||
|
|
3d964687fc | ||
|
|
ca18c6e552 | ||
|
|
cf9fe2d23f | ||
|
|
c13ab52138 | ||
|
|
58c5b50514 | ||
|
|
5020890c34 | ||
|
|
4d8060e8cb | ||
|
|
7a65311b1c | ||
|
|
186bbdcb87 | ||
|
|
bfef91f30a | ||
|
|
78c5ca28a0 | ||
|
|
90221f2149 | ||
|
|
263dcb4a79 | ||
|
|
cc1c0e1a38 | ||
|
|
04bf403861 | ||
|
|
5fe4226865 | ||
|
|
bddb987383 | ||
|
|
df1997c0dc | ||
|
|
954ba1fb7c | ||
|
|
e4152db482 | ||
|
|
dee7c7f1d0 | ||
|
|
e793f8979b | ||
|
|
d2dde69d14 | ||
|
|
49650eda62 | ||
|
|
76cd9bdf45 | ||
|
|
f95e339c03 | ||
|
|
db71be578e | ||
|
|
cb29c62c65 | ||
|
|
47e940272a | ||
|
|
8af43892f6 | ||
|
|
34609bd800 | ||
|
|
0b5d2cce55 | ||
|
|
d7fb4495f1 | ||
|
|
5e543cb620 | ||
|
|
3a258cbaad | ||
|
|
ba9e6f0c5c | ||
|
|
5d7ed18c50 | ||
|
|
2d221c1b67 | ||
|
|
f5bcbe5b0d | ||
|
|
6d73f74f83 | ||
|
|
bbf90c4623 | ||
|
|
2fca5edb7d | ||
|
|
d7f0fcc546 | ||
|
|
df825715ba | ||
|
|
2d5b12c01f | ||
|
|
753555744b | ||
|
|
d5eaa1895b | ||
|
|
b372bab52a | ||
|
|
a008308267 | ||
|
|
5d0fe32617 | ||
|
|
75d0dbff6d | ||
|
|
9c3343d1ee | ||
|
|
82daeb7c94 | ||
|
|
73fbf8e08d | ||
|
|
36e6de10c8 | ||
|
|
e1138b8190 | ||
|
|
589ef33e35 | ||
|
|
e4e7310c49 | ||
|
|
4611b24320 | ||
|
|
04eb5c04e6 | ||
|
|
e29dcbb023 | ||
|
|
d34fa527a0 | ||
|
|
35100b4e6f | ||
|
|
cd348dad21 | ||
|
|
aea25d2d4b | ||
|
|
4fff03f429 | ||
|
|
7c4152ce83 | ||
|
|
960ec8d2fd | ||
|
|
1426002037 | ||
|
|
193a6dd2a8 | ||
|
|
2d1aa6daea | ||
|
|
71af8cec42 | ||
|
|
3ac3c54b06 | ||
|
|
584e0283f5 | ||
|
|
62aa91f221 | ||
|
|
25b5d734c7 | ||
|
|
06aa5dbb1f | ||
|
|
8058b1718f | ||
|
|
956781ac1b | ||
|
|
3b9ea70e09 | ||
|
|
6e6f59b264 | ||
|
|
01e2494294 | ||
|
|
e3c8359e4e | ||
|
|
9accb6bb04 | ||
|
|
66961ad491 | ||
|
|
81665422b2 | ||
|
|
48ef95d104 | ||
|
|
bf240df083 | ||
|
|
d597f684b1 | ||
|
|
7acc1de7fa | ||
|
|
8a6e39d589 | ||
|
|
006549d661 | ||
|
|
233b3f0dd4 | ||
|
|
fdf89cd93f | ||
|
|
95c54f6cdb | ||
|
|
34237934d4 | ||
|
|
8c744569c4 | ||
|
|
458cb9fdad | ||
|
|
12b27415ea | ||
|
|
0701c9e4d7 | ||
|
|
42fd8a9e72 | ||
|
|
311edadd55 | ||
|
|
d8dd44d8eb | ||
|
|
41df8dc7f3 | ||
|
|
48beb58670 | ||
|
|
5e07a96c57 | ||
|
|
3ef09dac72 | ||
|
|
799aa6e19a | ||
|
|
aa6b547f55 | ||
|
|
f334dff09c | ||
|
|
055110dd35 | ||
|
|
745c7ab500 | ||
|
|
7cb5c55e13 | ||
|
|
0d7334a63f | ||
|
|
5754b81047 | ||
|
|
2aadd3ed41 | ||
|
|
d2a09c1753 | ||
|
|
c7756455cb | ||
|
|
4fcd233bf2 | ||
|
|
a73c19c14b | ||
|
|
6bf2b0bc4c | ||
|
|
d17f02979e | ||
|
|
716459f79d | ||
|
|
02263ca949 | ||
|
|
613b909765 | ||
|
|
f556430122 | ||
|
|
9390d450aa | ||
|
|
3d6f9456a3 | ||
|
|
27ee8f0132 | ||
|
|
678a0c2e71 | ||
|
|
11a2801231 | ||
|
|
d7565ee844 | ||
|
|
02bbdba792 | ||
|
|
f513f58d9e | ||
|
|
c036c9cc22 | ||
|
|
42458d838b | ||
|
|
b2794c18a1 | ||
|
|
760428fa46 | ||
|
|
76a3c1f28d | ||
|
|
2025ebfb96 | ||
|
|
5467c2ff5a | ||
|
|
843b958c9a | ||
|
|
7aa178acc9 | ||
|
|
2d722c93b8 | ||
|
|
b772251074 | ||
|
|
777fcade17 | ||
|
|
e370b19190 | ||
|
|
82b33ac4c7 | ||
|
|
fff5fde917 | ||
|
|
edffba3c2a | ||
|
|
11640196b2 | ||
|
|
6b0ef19caf | ||
|
|
d914ed3a89 | ||
|
|
b2743d785f | ||
|
|
2370a4e27b | ||
|
|
2fdd664594 | ||
|
|
b33ec65e5f | ||
|
|
3f2ad3fa8f | ||
|
|
e0101470ca | ||
|
|
86bb1a6764 | ||
|
|
96890821b0 | ||
|
|
0c0be92445 | ||
|
|
cc9b972e25 | ||
|
|
760e64b864 | ||
|
|
f6fa554077 | ||
|
|
bc8876b063 | ||
|
|
c30ac80d72 | ||
|
|
4de7b34c9f | ||
|
|
0edcf8b7e6 | ||
|
|
5feb0db212 | ||
|
|
703a8481c6 | ||
|
|
3413eeb058 | ||
|
|
a7b7f05b5b | ||
|
|
a07c5ece5d | ||
|
|
296f2a7ad2 | ||
|
|
e9708ba9f4 | ||
|
|
3c91de7a1e | ||
|
|
3c632d9e32 | ||
|
|
3821b2c537 | ||
|
|
ffad35c8db | ||
|
|
d28ad34bcb | ||
|
|
b8e58ee9ba | ||
|
|
b225ed4934 | ||
|
|
30383f9551 | ||
|
|
1f72512ef0 | ||
|
|
b8b02d8ef1 | ||
|
|
d8b1007f68 | ||
|
|
64993dbc7f | ||
|
|
4a4c5296f3 | ||
|
|
206fe7ccfb | ||
|
|
f1eab6a8a7 | ||
|
|
cd8fe4f6e2 | ||
|
|
bebcbd11ca | ||
|
|
fb1e5db6d7 | ||
|
|
910242c92b | ||
|
|
48b2c8fd37 | ||
|
|
d86abec6a2 | ||
|
|
1894f453f6 | ||
|
|
c35c84a279 | ||
|
|
a62a67ef5f | ||
|
|
d0c40851c0 | ||
|
|
52ada403ef | ||
|
|
b9786c763f | ||
|
|
6880198fda | ||
|
|
687a5607dc | ||
|
|
7b1a062e93 | ||
|
|
6a15a5339b | ||
|
|
a424d0915e | ||
|
|
458727bafb | ||
|
|
d7b527c1ae | ||
|
|
0fad3cfd03 | ||
|
|
7d9e05062e | ||
|
|
c8d9374491 | ||
|
|
f3028db073 | ||
|
|
d73bfbb98b | ||
|
|
42e1f9d5c6 | ||
|
|
b7841ad3aa | ||
|
|
4ea6cf0221 | ||
|
|
8f60fb29f4 | ||
|
|
96b95392ac | ||
|
|
16c1f0d3dc | ||
|
|
c675d0afb8 | ||
|
|
4c82bbecc3 | ||
|
|
faa56b1bcb | ||
|
|
e6caa931a5 | ||
|
|
6b45d4322b | ||
|
|
e92d54cadb | ||
|
|
444722cf38 | ||
|
|
b2b5c97105 | ||
|
|
d3772eb469 | ||
|
|
41732e4113 | ||
|
|
18bcfcd38e | ||
|
|
aa5a380996 | ||
|
|
68e6a15401 | ||
|
|
05ce91fb9e | ||
|
|
d2a159ed25 | ||
|
|
f66f7e484f | ||
|
|
fca42774f8 | ||
|
|
ef13ed06a3 | ||
|
|
fa35cdab99 | ||
|
|
8ed7da3f02 | ||
|
|
54f8205478 | ||
|
|
19531065ca | ||
|
|
4f5b5ccd48 | ||
|
|
ad8c77bfa3 | ||
|
|
8490a50304 | ||
|
|
aa174b3905 | ||
|
|
c006e5ece8 | ||
|
|
171d06965e | ||
|
|
6d9f861d0e | ||
|
|
041e3fd8da | ||
|
|
35d544b8c6 | ||
|
|
da34968ec3 | ||
|
|
35d44c97cc | ||
|
|
317eea64db | ||
|
|
2ef6ea4b96 | ||
|
|
c41f0164cc | ||
|
|
3cc866dd97 | ||
|
|
2929c41637 | ||
|
|
64e76db350 | ||
|
|
74fe4f6aba | ||
|
|
2e610158a8 | ||
|
|
65be1e5f8f | ||
|
|
9683fb6510 | ||
|
|
964663f1a4 | ||
|
|
e9668cc04b | ||
|
|
8a487271cb | ||
|
|
1a4cd4ca3d | ||
|
|
e116406ff1 | ||
|
|
34ba1eb083 | ||
|
|
6a455e7d29 | ||
|
|
6afc2fb4a8 | ||
|
|
c56b61d2bd | ||
|
|
c386733efd | ||
|
|
ecf0f4847f | ||
|
|
e031dc54e9 | ||
|
|
8e519e3e66 | ||
|
|
c52ba59d10 | ||
|
|
9ee5d06469 | ||
|
|
ec417833ee | ||
|
|
b4b81e290e | ||
|
|
c92f03d303 | ||
|
|
af06d49c33 | ||
|
|
e7270b3667 | ||
|
|
87cff6d5cb | ||
|
|
aaf9ef343b | ||
|
|
73cc666030 | ||
|
|
eaeeef3b80 | ||
|
|
73bb1e0f59 | ||
|
|
238038139d | ||
|
|
85e1c4ff0a | ||
|
|
a0d7039482 | ||
|
|
49a34037ad | ||
|
|
2dc9c26e36 | ||
|
|
2f3772b09a | ||
|
|
4a7fcb7d1c | ||
|
|
6e77d950eb | ||
|
|
572ae0dd46 | ||
|
|
a0a32abc0b | ||
|
|
edf7b060d2 | ||
|
|
2076ac9c38 | ||
|
|
4c9d59059e | ||
|
|
97de52a3be | ||
|
|
a994411e58 | ||
|
|
f06ba9f70b | ||
|
|
5a79873bd6 | ||
|
|
27f42beb81 | ||
|
|
6ccd2fa439 | ||
|
|
9dca93eeb2 | ||
|
|
11cc90d5f6 | ||
|
|
90495d0d5e | ||
|
|
f2136ec433 | ||
|
|
a04f27b255 | ||
|
|
f27875d5bc | ||
|
|
cb66d36434 | ||
|
|
d4ff718ac3 | ||
|
|
23fcac8c4f | ||
|
|
fa8165ba7e | ||
|
|
db9ca55c71 | ||
|
|
672e330f47 | ||
|
|
852e630314 | ||
|
|
54199b8d08 | ||
|
|
edc4814ced | ||
|
|
8f133a32ba | ||
|
|
4eb4e7ffdb | ||
|
|
acf4123234 | ||
|
|
9e843da98d | ||
|
|
e8ee36733f | ||
|
|
db3389a3cc | ||
|
|
3583825137 | ||
|
|
31079e0a60 | ||
|
|
45eed8f166 | ||
|
|
c038741194 | ||
|
|
63eaba4572 | ||
|
|
f2a3e50cab | ||
|
|
91b3e47243 | ||
|
|
b85fc019ca | ||
|
|
2c9b071fde | ||
|
|
6e83793dda | ||
|
|
2a5c08aaf8 | ||
|
|
5afaa731e0 | ||
|
|
bea25d1ceb | ||
|
|
739ca052b4 | ||
|
|
629fc03581 | ||
|
|
dd0337c3cf | ||
|
|
6b4188404b | ||
|
|
79ae65fe64 | ||
|
|
f6cf59c380 | ||
|
|
362a0c29ae | ||
|
|
be50c2f3f5 | ||
|
|
3917c774ec | ||
|
|
b708a8a4d3 | ||
|
|
80cd52701e | ||
|
|
265b03e400 | ||
|
|
4b9f1619f6 | ||
|
|
6438dee914 | ||
|
|
2a65a7aa8b | ||
|
|
2c689db6d7 | ||
|
|
2067d26276 | ||
|
|
aefa3c9ff6 | ||
|
|
3b2f6611d6 | ||
|
|
ecff5e1a3c | ||
|
|
eb33c9bf5a | ||
|
|
bd8fa031cc | ||
|
|
4d5b53aea2 | ||
|
|
69e96cba95 | ||
|
|
e836b6ce4c | ||
|
|
16bb0df9f9 | ||
|
|
bb7d389084 | ||
|
|
7a66b157f0 | ||
|
|
2fe53ac791 | ||
|
|
d0636d2b07 | ||
|
|
41ebe0e0bf | ||
|
|
6b8729a819 | ||
|
|
29f6d0e0e0 | ||
|
|
83349426d1 | ||
|
|
45647fdab3 | ||
|
|
67c2bf595f | ||
|
|
4d4b87ccb8 | ||
|
|
292149c46f | ||
|
|
704b1b4fdd | ||
|
|
a6a1754093 | ||
|
|
b0d3a77ac0 | ||
|
|
46ea733983 | ||
|
|
f4e313d3f2 | ||
|
|
1924eb9197 | ||
|
|
952d1eb76f | ||
|
|
f2934bd0bd | ||
|
|
677f570f34 | ||
|
|
227c19bb67 | ||
|
|
1f605df053 | ||
|
|
17d1a471a4 | ||
|
|
f00c1389d6 | ||
|
|
4f35f8cad8 | ||
|
|
5ea4a626a6 | ||
|
|
4bb273a802 | ||
|
|
4a47ea034b | ||
|
|
7b9fbc4389 | ||
|
|
2883b67644 | ||
|
|
f788c789f3 | ||
|
|
3e8c3ab0c4 | ||
|
|
ff991ac99e | ||
|
|
a14547e92f | ||
|
|
203f5b48ad | ||
|
|
7bdfb1f55f | ||
|
|
cf3e1e7e7d | ||
|
|
fd36fc0ea2 | ||
|
|
eb9ddbe8a9 | ||
|
|
256044c04f | ||
|
|
0cd55d88bf | ||
|
|
bba1f964b8 | ||
|
|
7015501161 | ||
|
|
ff0b1cfb0b | ||
|
|
d90b02ce22 | ||
|
|
5b62b4a884 | ||
|
|
f7d127b360 | ||
|
|
1d7d4c2446 | ||
|
|
a85d5f57bb | ||
|
|
1a414f5512 | ||
|
|
e24c1302f4 | ||
|
|
883199093c | ||
|
|
6a3d61ff12 | ||
|
|
c4e94a4130 | ||
|
|
a921e88d76 | ||
|
|
a56e14488e | ||
|
|
55cefa9021 | ||
|
|
3484df9ca4 | ||
|
|
66288296b2 | ||
|
|
5bffcb4c89 | ||
|
|
4867571df0 | ||
|
|
a2250dd205 | ||
|
|
f053fc48db |
30
.editorconfig
Normal file
30
.editorconfig
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
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
|
||||
2
.github/.ignore_words
vendored
Normal file
2
.github/.ignore_words
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
gool
|
||||
Cant
|
||||
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
116
.github/workflows/ci.yml
vendored
Normal file
116
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code.
|
||||
uses: actions/checkout@v7
|
||||
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 }}"
|
||||
- name: 'Check Generated Manuals'
|
||||
run: |
|
||||
failed=0
|
||||
while IFS= read -r source; do
|
||||
case "$source" in
|
||||
man/git-*.md)
|
||||
stem=${source%.md}
|
||||
for generated in "$stem.1" "$stem.html"; do
|
||||
if ! grep -Fqx -- "$generated" <<< "$CHANGED_FILES"; then
|
||||
echo "::error file=$source::$generated must be updated with $source"
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
done <<< "$CHANGED_FILES"
|
||||
exit "$failed"
|
||||
env:
|
||||
CHANGED_FILES: "${{ steps.files.outputs.added_modified }}"
|
||||
- uses: 'actions/setup-go@v7'
|
||||
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
|
||||
|
||||
typo:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code.
|
||||
uses: actions/checkout@v7
|
||||
- name: Install codespell
|
||||
run: python3 -m pip install codespell==2.4
|
||||
- name: spell check
|
||||
run: |
|
||||
git grep --cached -l '' . | \
|
||||
grep -v -e 'History\.md' -e 'AUTHORS' -e 'man/.*\.1' -e 'man/.*\.html' | \
|
||||
xargs codespell --ignore-words=.github/.ignore_words
|
||||
|
||||
test-bats:
|
||||
name: 'Test with Bats'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
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@v7
|
||||
- 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"
|
||||
18
.github/workflows/stale.yaml
vendored
Normal file
18
.github/workflows/stale.yaml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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@v11"
|
||||
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
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.venv/
|
||||
__pycache__/
|
||||
coverage/
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "vendor/bats-all"]
|
||||
path = vendor/bats-all
|
||||
url = https://github.com/hyperupcall/bats-all
|
||||
5
.pytest.ini
Normal file
5
.pytest.ini
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[pytest]
|
||||
minversion = 7.4
|
||||
addopts = -ra -q
|
||||
testpaths = tests
|
||||
faulthandler_timeout = 5
|
||||
14
.travis.yml
14
.travis.yml
|
|
@ -1,14 +0,0 @@
|
|||
os:
|
||||
- linux
|
||||
- osx
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- bsdmainutils
|
||||
script:
|
||||
- ./check_integrity.sh $(find bin | cut -b 5- | xargs)
|
||||
# Test for the brew release
|
||||
- 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"
|
||||
113
AUTHORS
113
AUTHORS
|
|
@ -1,66 +1,92 @@
|
|||
git-extras is written and maintained by TJ Holowaychuk and
|
||||
various contributors:
|
||||
|
||||
Development Lead
|
||||
````````````````
|
||||
- TJ Holowaychuk <tj@vision-media.ca>
|
||||
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-
|
||||
- timfeirg
|
||||
- CJ
|
||||
- Paul Wise
|
||||
- Damien Tardy-Panis
|
||||
- Mark Eissler
|
||||
- Yuriy VG
|
||||
- Leila Muhtasib
|
||||
- Richard Fearn
|
||||
- Paul Wise
|
||||
- Bill Wood
|
||||
- Jesús Espino
|
||||
- Rémy HUBSCHER
|
||||
- go2null
|
||||
- Andrew Janke
|
||||
- David Baumgold
|
||||
- Jan Schulz
|
||||
- Kenneth Reitz
|
||||
- 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
|
||||
- grindhold
|
||||
- wyattscarpenter
|
||||
- Aggelos Orfanakos
|
||||
- Camille Reynders
|
||||
- Carlos Prado
|
||||
- Chris Hall
|
||||
- Damian Krzeminski
|
||||
- NANRI
|
||||
- Alexander Krasnukhin
|
||||
- Phally
|
||||
- Rico Sta. Cruz
|
||||
- Rémy HUBSCHER
|
||||
- Takuma Yamaguchi
|
||||
- thomas menzel
|
||||
- vr8ce
|
||||
- Brian J Brennan
|
||||
- Dominik Gedon
|
||||
- Hogan Long
|
||||
- Ivan Malopinsky
|
||||
- John Bachir
|
||||
- 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
|
||||
- Daniele Paolella
|
||||
- David Rogers
|
||||
- Devin Withers
|
||||
- Domenico Rotiroti
|
||||
|
|
@ -69,7 +95,9 @@ Patches and Suggestions
|
|||
- Gert Van Gool
|
||||
- Guillaume Seren
|
||||
- Hozefa
|
||||
- Igor Ostapenko
|
||||
- Jean Jordaan
|
||||
- Joshua Li
|
||||
- Justin Guenther
|
||||
- Kylie McClain
|
||||
- Marc Harter
|
||||
|
|
@ -84,36 +112,46 @@ Patches and Suggestions
|
|||
- Wil Moore III
|
||||
- William Montgomery
|
||||
- Ye Lin Aung
|
||||
- go2null
|
||||
- phigoro
|
||||
- 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
|
||||
- Brice Dutheil
|
||||
- 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
|
||||
|
|
@ -124,86 +162,135 @@ Patches and Suggestions
|
|||
- Dominic Barnes
|
||||
- Dung Quang
|
||||
- Edward Betts
|
||||
- Eli Schwartz
|
||||
- Emil Kjelsrud
|
||||
- Erik Skultety
|
||||
- François M
|
||||
- George Crabtree
|
||||
- Gerrit-K
|
||||
- Greg Allen
|
||||
- Guilhem Saurel
|
||||
- Guillermo Rauch
|
||||
- Gunnlaugur Thor Briem
|
||||
- Hasse Ramlev Hansen
|
||||
- Heiko Becker
|
||||
- Hugo Ruiz-Mireles
|
||||
- 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
|
||||
- Justin Dugger
|
||||
- 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
|
||||
- Ricardo Fernández Serrata
|
||||
- Riceball LEE
|
||||
- Rob Kennedy
|
||||
- Robin von Bülow
|
||||
- Russ
|
||||
- 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
|
||||
- johnpyp
|
||||
- jykntr
|
||||
- kang
|
||||
- meza
|
||||
- neydroid
|
||||
- nulltask
|
||||
- phanium
|
||||
- sgleizes
|
||||
- tfendin
|
||||
- tiemonl
|
||||
- zentarul
|
||||
- zeroDivisible
|
||||
- zhiyanfoo
|
||||
- Áron Hoffmann
|
||||
- Étienne BERSAC
|
||||
- ☃ pitr
|
||||
- 单元源
|
||||
|
|
|
|||
|
|
@ -1,21 +1,34 @@
|
|||
## Your new git-extra command should support
|
||||
# Contributing
|
||||
|
||||
* OSX, Linux, BSD (You may need to browse their man page)<sup>*</sup>
|
||||
* Bash 3.2+ (If you aren't sure, see [the Bash changelog](http://tldp.org/LDP/abs/html/bash2.html))
|
||||
* Git 2.1+
|
||||
Thanks for contributing! Please read this document before you make a PR.
|
||||
|
||||
<sup>*</sup>If you aren't able to test your new command on a platform,
|
||||
make that clear in your PR and someone else may be able to test it on their system.
|
||||
## Supported Platforms
|
||||
|
||||
## To submit a new command, you should
|
||||
Any changes must support the following platforms:
|
||||
|
||||
Let's assume your new command is named `foo`.
|
||||
- macOS
|
||||
- Linux
|
||||
- OpenBSD (You may need to browse their man page)
|
||||
|
||||
1. Write a bash script under `./bin` called `git-foo`.
|
||||
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. Run `./check_integrity.sh foo` to check if all done.
|
||||
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`.
|
||||
|
|
|
|||
435
Commands.md
435
Commands.md
|
|
@ -1,29 +1,36 @@
|
|||
|
||||
- [`git abort`](#git-abort)
|
||||
- [`git alias`](#git-alias)
|
||||
- [`git archive-file`](#git-archive-file)
|
||||
- [`git authors`](#git-authors)
|
||||
- [`git back`](#git-back)
|
||||
- [`git bug`](#git-featurerefactorbugchore)
|
||||
- [`git browse`](#git-browse)
|
||||
- [`git browse-ci`](#git-browse-ci)
|
||||
- [`git bulk`](#git-bulk)
|
||||
- [`git brv`](#git-brv)
|
||||
- [`git changelog`](#git-changelog)
|
||||
- [`git chore`](#git-featurerefactorbugchore)
|
||||
- [`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-gone-branches`](#git-delete-gone-branches)
|
||||
- [`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-featurerefactorbugchore)
|
||||
- [`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)
|
||||
|
|
@ -33,19 +40,21 @@
|
|||
- [`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 refactor`](#git-featurerefactorbugchore)
|
||||
- [`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)
|
||||
|
|
@ -66,6 +75,9 @@
|
|||
- [`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
|
||||
|
||||
|
|
@ -74,7 +86,7 @@ The main `git-extras` command.
|
|||
Output the current `--version`:
|
||||
|
||||
```bash
|
||||
$ git extras
|
||||
$ git extras --version
|
||||
```
|
||||
|
||||
List available commands:
|
||||
|
|
@ -90,11 +102,11 @@ $ git extras update
|
|||
```
|
||||
## git gh-pages
|
||||
|
||||
Sets up the `gh-pages` branch. (See [GitHub Pages](http://pages.github.com/) documentation.)
|
||||
Sets up the `gh-pages` branch. (See [GitHub Pages](https://pages.github.com/) documentation.)
|
||||
|
||||
## git feature|refactor|bug|chore
|
||||
## git feature
|
||||
|
||||
Create/Merge the given feature, refactor, bug or chore branch `name`:
|
||||
Create/Merge the given feature branch `name`:
|
||||
|
||||
```bash
|
||||
$ git feature dependencies
|
||||
|
|
@ -123,8 +135,6 @@ $ git feature finish dependencies
|
|||
|
||||
_Note_: If a remote is setup to track the branch, it will be deleted.
|
||||
|
||||
All of this works with `feature`, `bug`, `chore` or `refactor`.
|
||||
|
||||
## git contrib
|
||||
|
||||
Output `author`'s contributions to a project:
|
||||
|
|
@ -142,17 +152,20 @@ visionmedia (18):
|
|||
|
||||
## git summary
|
||||
|
||||
Outputs a repo summary:
|
||||
Outputs a repo or path summary:
|
||||
|
||||
```bash
|
||||
$ git summary
|
||||
|
||||
project : git-extras
|
||||
repo age : 10 months ago
|
||||
commits : 163
|
||||
active : 60 days
|
||||
files : 93
|
||||
authors :
|
||||
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%
|
||||
|
|
@ -169,8 +182,8 @@ authors :
|
|||
1 Guillermo Rauch 0.6%
|
||||
```
|
||||
|
||||
This command can also take a *commitish*, and will print a summary for commits in
|
||||
the commitish range:
|
||||
This command can also take a *committish*, and will print a summary for commits in
|
||||
the committish range:
|
||||
|
||||
```bash
|
||||
$ git summary v42..
|
||||
|
|
@ -213,6 +226,20 @@ project : git-extras
|
|||
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.
|
||||
|
|
@ -221,8 +248,6 @@ project : git-extras
|
|||
node (master): git effort --above 15 {src,lib}/*
|
||||
```
|
||||
|
||||

|
||||
|
||||
If you wish to ignore files with commits `<=` a value you may use `--above`:
|
||||
|
||||
```
|
||||
|
|
@ -251,17 +276,40 @@ $ git effort bin/* lib/*
|
|||
|
||||
```bash
|
||||
usage: git bulk [-g] ([-a]|[-w <ws-name>]) <git command>
|
||||
git bulk --addworkspace <ws-name> <ws-root-directory>
|
||||
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 (notice that <ws-root-directory> must be absolute path):
|
||||
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`
|
||||
|
|
@ -275,6 +323,7 @@ $ git bulk --addcurrent personal
|
|||
```bash
|
||||
$ git bulk --listall
|
||||
bulkworkspaces.personal /Users/niklasschlimm/workspaces/personal
|
||||
|
||||
```
|
||||
|
||||
Run a git command on the repositories of the current workspace:
|
||||
|
|
@ -314,21 +363,78 @@ $ git bulk --removeworkspace personal
|
|||
$ 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. Let's you run `git` commands without typing 'git'.
|
||||
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` or `quit` to end the repl session.
|
||||
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.9.2
|
||||
git-extras version 3.0.0
|
||||
type 'ls' to ls files below current directory,
|
||||
'!command' to execute any command or just 'subcommand' to execute any git subcommand
|
||||
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
|
||||
|
|
@ -347,6 +453,30 @@ 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"):
|
||||
|
|
@ -482,6 +612,20 @@ $ git rename-branch old-name new-name
|
|||
$ 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).
|
||||
|
|
@ -630,14 +774,14 @@ build
|
|||
|
||||
## git ignore-io
|
||||
|
||||
Generate sample gitignore file from [gitignore.io](https://www.gitignore.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.gitignore.io/api/vim
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/vim
|
||||
|
||||
### Vim ###
|
||||
[._]*.s[a-w][a-z]
|
||||
|
|
@ -698,6 +842,13 @@ $ git info
|
|||
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
|
||||
|
|
@ -705,8 +856,6 @@ $ git info
|
|||
|
||||
Added git-info command.
|
||||
|
||||
Type 'git log' for more commits, or 'git show <commit id>' for full commit details.
|
||||
|
||||
## Configuration (.git/config):
|
||||
|
||||
color.diff=auto
|
||||
|
|
@ -732,6 +881,14 @@ If you wish to omit the config section, you may use `--no-config`:
|
|||
$ 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`:
|
||||
|
|
@ -776,6 +933,21 @@ Delete local and remote tag `name`:
|
|||
$ git delete-tag 0.0.1
|
||||
```
|
||||
|
||||
## git delete-gone-branches
|
||||
|
||||
Deletes all local branches whose remote-tracking branch has been deleted (i.e. branches shown as `[gone]` in `git branch -vv`). Use `--dry-run` to preview what would be deleted.
|
||||
|
||||
```bash
|
||||
$ git delete-gone-branches
|
||||
Deleted branch feature-123 (was abc1234).
|
||||
Deleted branch feature-456 (was def5678).
|
||||
|
||||
$ git delete-gone-branches --dry-run
|
||||
Would delete the following branches:
|
||||
feature-123
|
||||
feature-456
|
||||
```
|
||||
|
||||
## git delete-merged-branches
|
||||
|
||||
Deletes branches that are listed in `git branch --merged`.
|
||||
|
|
@ -788,14 +960,34 @@ 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 `name`:
|
||||
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
|
||||
|
|
@ -850,9 +1042,7 @@ $ git squash HEAD~3 "Work on a feature"
|
|||
|
||||
Populates the file matching `authors|contributors -i` with the authors of commits, according to the number of commits per author.
|
||||
|
||||
Opens the file in `$EDITOR` when set.
|
||||
|
||||
See the ["MAPPING AUTHORS" section](http://git-scm.com/docs/git-shortlog#_mapping_authors) of **git-shortlog**(1) to coalesce together commits by the same person.
|
||||
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:
|
||||
|
||||
|
|
@ -890,15 +1080,6 @@ nickl-
|
|||
Leila Muhtasib
|
||||
```
|
||||
|
||||
## git back
|
||||
|
||||
Removes the latest commits, and add their changes to your staging area.
|
||||
|
||||
```
|
||||
$ git back # Removes the latest commit.
|
||||
$ git back 3 # Remove the latest 3 commits.
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
|
@ -1003,6 +1184,13 @@ git undo 3
|
|||
|
||||
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.
|
||||
|
|
@ -1015,6 +1203,14 @@ 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.
|
||||
|
||||
The following options are available (must precede `<remote>`):
|
||||
|
||||
```bash
|
||||
-v, --verbose Print what will be synced before syncing
|
||||
-i, --interactive Prompt for confirmation before syncing (implies --verbose)
|
||||
-n, --dry-run Show what would be synced, change nothing (implies --verbose)
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Copy unstaged files to remote. Useful when you want to make quick test without making any commits
|
||||
|
|
@ -1171,11 +1367,11 @@ List all commits on the local branch that have not yet been sent to origin. Any
|
|||
|
||||
## git archive-file
|
||||
|
||||
Creates an zip archive of the current git repository. The name of the archive will depend on the current HEAD of your git repository.
|
||||
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.
|
||||
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
|
||||
|
|
@ -1183,6 +1379,12 @@ $ git missing master
|
|||
> 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`:
|
||||
|
|
@ -1226,8 +1428,8 @@ $ git reset-file .htaccess dc82b19
|
|||
|
||||
## git mr
|
||||
|
||||
Checks out a merge request from GitLab. Usage: `git mr <ID|URL> [REMOTE]`.
|
||||
Default remote is `origin`.
|
||||
Checks out a merge request from GitLab, or a pull request from Forgejo/Codeberg.
|
||||
Usage: `git mr <ID|URL> [REMOTE]`. Default remote is `origin`.
|
||||
|
||||
``` bash
|
||||
$ git mr 51
|
||||
|
|
@ -1239,15 +1441,48 @@ 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
|
||||
$ 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'
|
||||
```
|
||||
|
||||
A Forgejo/Codeberg pull request URL is also supported:
|
||||
|
||||
``` bash
|
||||
$ git mr https://codeberg.org/owner/repository/pulls/51
|
||||
From codeberg.org:owner/repository
|
||||
* [new ref] refs/pull/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
|
||||
|
|
@ -1396,3 +1631,99 @@ 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
|
||||
```
|
||||
|
|
|
|||
537
History.md
537
History.md
|
|
@ -1,4 +1,539 @@
|
|||
|
||||
7.5.0 / 2026-05-09
|
||||
==================
|
||||
|
||||
* Use standard prefix for home dir installs (#1248)
|
||||
* refactor(abort): common `gitdir` (#1244)
|
||||
* Fix man page usage docs (#1241)
|
||||
* Fix `git-changelog` to handle whitespace in command arguments (#1232)
|
||||
* chore(deps): bump bats-core/bats-action from 3.0.1 to 4.0.0 (#1230)
|
||||
* add details when multiple active operations found (#1229)
|
||||
* Add persistent history to `git-repl` (#1226)
|
||||
* Support passing ref to `git-commits-since` (#1228)
|
||||
* ability to specify command when hitting enter (#1223)
|
||||
* Improve `git-repl` prompt (#1224)
|
||||
* feat: `delete-branch` multiple unique branch names completions (#1221)
|
||||
* chore(deps): bump actions/checkout from 5 to 6 (#1219)
|
||||
* Made Git Magic use `--force-with-lease` (#1218)
|
||||
* chore(deps): bump actions/stale from 9 to 10 (#1214)
|
||||
* chore(deps): bump actions/setup-go from 5 to 6 (#1215)
|
||||
* chore(deps): bump actions/setup-python from 5 to 6 (#1216)
|
||||
* Fix minor typo in `git rename-branch` man page (#1211)
|
||||
* Improvements to Bash completion (#1210)
|
||||
* Fix use of `git-whatchanged` to `git-log` (#1212)
|
||||
* chore(deps): bump actions/checkout from 4 to 5 (#1209)
|
||||
* Bump version to 7.5.0-dev (#1207)
|
||||
|
||||
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
|
||||
==================
|
||||
|
||||
|
|
@ -38,7 +573,7 @@
|
|||
|
||||
* git-pr: emphasized that the remote is required when pulling multiple PRs.
|
||||
* Merge pull request #743 from spacewander/allow_multiple_pr
|
||||
* git-pr: accpeted multiple GitHub URL or ID with remote.
|
||||
* 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.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,31 @@
|
|||
# Installing git-extras
|
||||
# Installation
|
||||
|
||||
## Dependencies
|
||||
|
||||
Some commands require extra dependencies which are unavailable in some platforms.
|
||||
You may need to install them manually.
|
||||
You may need to install them manually. They are:
|
||||
|
||||
Those dependencies are listed below:
|
||||
* 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`)
|
||||
|
||||
* column
|
||||
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.
|
||||
|
||||
[](https://repology.org/project/git-extras/versions)
|
||||
|
||||
### Debian
|
||||
|
||||
```bash
|
||||
|
|
@ -24,6 +39,20 @@ $ sudo $apt_pref install git-extras
|
|||
$ 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
|
||||
|
|
@ -46,8 +75,7 @@ $ nix-env -i git-extras
|
|||
|
||||
[Abdullah](https://github.com/AWAN) has written a [Pkgfile](https://abdullah.today/ports/git-extras/Pkgfile) for his beloved [distro](https://crux.nu).
|
||||
|
||||
|
||||
### Mac OS X with Homebrew
|
||||
### Homebrew
|
||||
|
||||
```bash
|
||||
$ brew install git-extras
|
||||
|
|
@ -55,7 +83,6 @@ $ 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/)
|
||||
|
|
@ -65,6 +92,7 @@ Installing from Homebrew will not give you the option omit certain `git-extras`
|
|||
|
||||
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)
|
||||
|
|
@ -87,6 +115,12 @@ 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`.
|
||||
|
|
@ -110,7 +144,7 @@ alternate location, specify a `PREFIX` when calling `make`.
|
|||
|
||||
```bash
|
||||
# Non-root users can install under their home directory
|
||||
make install PREFIX=$HOME/software
|
||||
make install PREFIX=$HOME/.local
|
||||
|
||||
# For third-party software kept under /opt
|
||||
make install PREFIX=/opt
|
||||
|
|
@ -120,7 +154,7 @@ If you want to relocate the bulk of the installation but still have configuratio
|
|||
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
|
||||
```
|
||||
|
||||
|
|
@ -131,19 +165,24 @@ See the Makefile for details on advanced configuration options.
|
|||
One-liner:
|
||||
|
||||
```bash
|
||||
curl -sSL http://git.io/git-extras-setup | sudo bash /dev/stdin
|
||||
curl -sSL https://raw.githubusercontent.com/tj/git-extras/main/install.sh | sudo bash /dev/stdin
|
||||
```
|
||||
|
||||
## Installing as Zsh plugin
|
||||
|
||||
[Zplugin](https://github.com/zdharma/zplugin) can install git-extras by using:
|
||||
[ZInit](https://github.com/zdharma/zinit) can install git-extras by using:
|
||||
|
||||
```zsh
|
||||
zplugin ice as"program" pick"$ZPFX/bin/git-*" make"PREFIX=$ZPFX"
|
||||
zplugin light tj/git-extras
|
||||
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 `~/.zplugin/polaris` by default. Use `zplugin update tj/git-extras` to update.
|
||||
`$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
|
||||
|
|
@ -154,4 +193,4 @@ If you installed git-extras from source, you can run `git-extras update` to upda
|
|||
|
||||
Enjoy `git-extras`!
|
||||
|
||||
[1]: http://sourceforge.net/projects/msys2/
|
||||
[1]: https://sourceforge.net/projects/msys2/
|
||||
|
|
|
|||
48
Makefile
48
Makefile
|
|
@ -1,14 +1,25 @@
|
|||
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
|
||||
|
||||
SYSCONFDIR ?= $(PREFIX)/etc
|
||||
BINS = $(wildcard bin/git-*)
|
||||
MANS = $(wildcard man/git-*.md)
|
||||
MAN_BINS = $(filter-out man/git-extras.md, $(MANS))
|
||||
|
|
@ -34,22 +45,24 @@ 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)"
|
||||
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)}'))
|
||||
git config --get-regexp 'alias\..*' | awk '{print "git-" substr($$1, 7)}'))
|
||||
@$(foreach COMMAND, $(COMMANDS), \
|
||||
disable=''; \
|
||||
if test ! -z "$(filter $(COMMAND), $(EXISTED_ALIASES))"; then \
|
||||
read -p "$(COMMAND) conflicts with an alias, still install it and disable the alias? [y/n]" answer; \
|
||||
test "$$answer" = 'n' -o "$$answer" = 'N' && disable="true"; \
|
||||
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 test -z "$$disable"; then \
|
||||
if [ "$$should_install" = 'yes' ]; then \
|
||||
echo "... installing $(COMMAND)"; \
|
||||
head -1 bin/$(COMMAND) > $(TEMPFILE); \
|
||||
cat $(LIB) >> $(TEMPFILE); \
|
||||
|
|
@ -69,11 +82,13 @@ install: check
|
|||
cp -f man/git-*.1 $(DESTDIR)$(MANPREFIX); \
|
||||
echo "cp -f man/git-*.1 $(DESTDIR)$(MANPREFIX)"; \
|
||||
fi
|
||||
@mkdir -p $(DESTDIR)$(SYSCONFDIR)/bash_completion.d
|
||||
cp -f etc/bash_completion.sh $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/git-extras
|
||||
@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
|
||||
|
|
@ -117,7 +132,7 @@ uninstall:
|
|||
echo "... uninstalling $(DESTDIR)$(MANPREFIX)/$(notdir $(MAN))"; \
|
||||
rm -f $(DESTDIR)$(MANPREFIX)/$(notdir $(MAN)); \
|
||||
)
|
||||
rm -f $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/git-extras
|
||||
rm -f $(COMPL_DIR)/git-extras
|
||||
|
||||
clean: docclean
|
||||
|
||||
|
|
@ -125,4 +140,7 @@ docclean:
|
|||
rm -f man/*.1
|
||||
rm -f man/*.html
|
||||
|
||||
.PHONY: default docs clean docclean check install uninstall
|
||||
test:
|
||||
bats ./tests
|
||||
|
||||
.PHONY: default docs check install uninstall clean docclean test
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
MANPREFIX ?= /doc/git/html
|
||||
BINS = $(wildcard bin/git-*)
|
||||
MANS = $(wildcard man/git-*.md)
|
||||
MAN_HTML = $(MANS:.md=.html)
|
||||
|
||||
install:
|
||||
@mkdir -p $(DESTDIR)$(MANPREFIX)
|
||||
@mkdir -p $(DESTDIR)/bin
|
||||
@echo "... installing bins to $(DESTDIR)/bin"
|
||||
@echo "... installing man pages to $(DESTDIR)$(MANPREFIX)"
|
||||
@$(foreach BIN, $(BINS), \
|
||||
echo "... installing `basename $(BIN)`"; \
|
||||
cp -f $(BIN) $(DESTDIR)/$(BIN); \
|
||||
)
|
||||
cp -f man/git-*.html $(DESTDIR)$(MANPREFIX)
|
||||
@mkdir -p $(DESTDIR)/etc/bash_completion.d
|
||||
cp -f etc/bash_completion.sh $(DESTDIR)/etc/bash_completion.d/git-extras
|
||||
|
||||
uninstall:
|
||||
@$(foreach BIN, $(BINS), \
|
||||
echo "... uninstalling $(DESTDIR)/$(BIN)"; \
|
||||
rm -f $(DESTDIR)/$(BIN); \
|
||||
)
|
||||
@$(foreach MAN, $(MAN_HTML), \
|
||||
echo "... uninstalling $(DESTDIR)$(MANPREFIX)/`basename $(MAN)`"; \
|
||||
rm -f "$(DESTDIR)$(MANPREFIX)/`basename $(MAN)`"; \
|
||||
)
|
||||
rm -f $(DESTDIR)/etc/bash_completion.d/git-extras
|
||||
|
||||
.PHONY: install uninstall
|
||||
23
Readme.md
23
Readme.md
|
|
@ -1,21 +1,34 @@
|
|||
# Git Extras
|
||||
|
||||
[](https://gitter.im/tj/git-extras)
|
||||
|
||||
Little git extras.
|
||||
|
||||
## Screencasts
|
||||
|
||||
Just getting started? Check out these screencasts:
|
||||
|
||||
* [introduction](https://vimeo.com/45506445) -- covering git-ignore, git-setup, git-changelog, git-release, git-effort and more
|
||||
* [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 [Installation](Installation.md) page.
|
||||
See the [Installation](Installation.md) page.
|
||||
|
||||
## Commands
|
||||
|
||||
Go to [Commands](Commands.md) page for basic usage and examples.
|
||||
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`.
|
||||
|
|
|
|||
45
bin/git-abort
Executable file
45
bin/git-abort
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 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
|
||||
|
||||
discover_op() {
|
||||
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
|
||||
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"
|
||||
|
|
@ -1,16 +1,45 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
options=""
|
||||
|
||||
usage() {
|
||||
cat <<HERE
|
||||
usage: git alias # list all aliases
|
||||
or: git alias <search-pattern> # show aliases matching pattern
|
||||
or: git alias <alias-name> <command> # alias a command
|
||||
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) git config --get-regexp 'alias.*' | sed 's/^alias\.//' | sed 's/[ ]/ = /' | sort ;;
|
||||
1) git alias | grep -e "$1" ;;
|
||||
2) git config --global alias."$1" "$2" ;;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,34 +1,37 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# extract current branch name
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null)
|
||||
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 $(pwd))
|
||||
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
|
||||
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" = "master" ]; then
|
||||
FILENAME=$ARCHIVE_NAME.$VERSION.zip
|
||||
else
|
||||
FILENAME=$ARCHIVE_NAME.$VERSION.$BRANCH.zip
|
||||
fi
|
||||
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
|
||||
OUTPUT=$PWD/$FILENAME
|
||||
|
||||
# building archive
|
||||
git archive --format zip --output $OUTPUT $BRANCH
|
||||
git archive --format zip --output "$OUTPUT" "$BRANCH"
|
||||
|
||||
# also display size of the resulting file
|
||||
echo Saved to \"$FILENAME\" \(`du -h $OUTPUT | cut -f1`\)
|
||||
echo Saved to \""$FILENAME"\" \("$(du -h "$OUTPUT" | cut -f1)"\)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
LIST=false
|
||||
NO_EMAIL=false
|
||||
FILE=""
|
||||
EDITOR=$(git var GIT_EDITOR)
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
|
|
@ -22,9 +21,9 @@ done
|
|||
|
||||
if ! $LIST; then
|
||||
FILE=$1
|
||||
if test "$FILE" = ""; then
|
||||
FILE=$(ls | egrep 'authors|contributors' -i|head -n1)
|
||||
if test "$FILE" = ""; then
|
||||
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
|
||||
|
|
@ -36,11 +35,11 @@ fi
|
|||
|
||||
authors() {
|
||||
if $NO_EMAIL; then
|
||||
# eamil will be used to uniq authors.
|
||||
git shortlog -sne | awk '{$1=""; sub(" ", ""); print}' | awk -F'<' '!x[$1]++' | awk -F'<' '!x[$2]++' \
|
||||
# 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 -sne | awk '{$1=""; sub(" ", ""); print}' | awk -F'<' '!x[$1]++' | awk -F'<' '!x[$2]++'
|
||||
git shortlog HEAD -sne | awk '{$1=""; sub(" ", ""); print}' | awk -F'<' '!x[$1]++' | awk -F'<' '!x[$2]++'
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +50,5 @@ authors() {
|
|||
if $LIST; then
|
||||
authors
|
||||
else
|
||||
authors >> $FILE
|
||||
test -n "$EDITOR" && $EDITOR $FILE
|
||||
authors >> "$FILE"
|
||||
fi
|
||||
|
|
|
|||
11
bin/git-back
11
bin/git-back
|
|
@ -1,11 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if test $# -eq 0; then
|
||||
git reset --soft HEAD~1
|
||||
else
|
||||
if `echo $1 | grep -q [^[:digit:]]`; then
|
||||
echo "$1 is not a number" 1>&2
|
||||
else
|
||||
git reset --soft HEAD~$1
|
||||
fi
|
||||
fi
|
||||
92
bin/git-browse
Executable file
92
bin/git-browse
Executable file
|
|
@ -0,0 +1,92 @@
|
|||
#!/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
|
||||
60
bin/git-browse-ci
Executable file
60
bin/git-browse-ci
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
#!/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
|
||||
81
bin/git-brv
Executable file
81
bin/git-brv
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#!/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
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ALIAS=bug
|
||||
git feature -a $ALIAS "$@"
|
||||
189
bin/git-bulk
189
bin/git-bulk
|
|
@ -1,124 +1,185 @@
|
|||
#!/usr/bin/env bash
|
||||
invers=$(tput rev)
|
||||
inverse=$(tput rev)
|
||||
reset=$(tput sgr0)
|
||||
txtbld=$(tput bold)
|
||||
bldred=${txtbld}$(tput setaf 1)
|
||||
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 [-g] ([-a]|[-w <ws-name>]) <git command>"
|
||||
echo 1>&2 " git bulk --addworkspace <ws-name> <ws-root-directory>"
|
||||
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
|
||||
function addworkspace { git config --global bulkworkspaces."$wsname" "$wsdir"; }
|
||||
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
|
||||
function addcurrent { git config --global bulkworkspaces."$wsname" "$PWD"; }
|
||||
addcurrent() { git config --global bulkworkspaces."$wsname" "$PWD"; }
|
||||
|
||||
# remove workspace from global git config
|
||||
function removeworkspace { checkWSName && git config --global --unset bulkworkspaces."$wsname"; }
|
||||
removeworkspace() { checkWSName && git config --global --unset bulkworkspaces."$wsname"; }
|
||||
|
||||
# remove workspace from global git config
|
||||
function purge { git config --global --remove-section bulkworkspaces; }
|
||||
purge() { git config --global --remove-section bulkworkspaces; }
|
||||
|
||||
# list all current workspace locations defined
|
||||
function listall { git config --global --get-regexp bulkworkspaces; }
|
||||
listall() { git config --global --get-regexp bulkworkspaces; }
|
||||
|
||||
# guarded execution of a git command in one specific repository
|
||||
function guardedExecution () {
|
||||
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 -n "${invers}git $gitcommand${reset} -> execute here (y/n)? "
|
||||
read -n 1 -r </dev/tty; echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then atomicExecution; fi
|
||||
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
|
||||
atomicExecution
|
||||
git "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# atomic git command execution with log
|
||||
function atomicExecution () {
|
||||
echo "${bldred}->${reset} executing ${invers}git $gitcommand${reset}" && git $gitcommand
|
||||
}
|
||||
|
||||
# check if the passed command is known as a core git command
|
||||
function checkGitCommand () {
|
||||
checkGitCommand () {
|
||||
if git help -a | grep -o -q "\b${corecommand}\b"; then
|
||||
echo "Core command \"$corecommand\" accepted."
|
||||
echo 1>&2 "Core command \"$corecommand\" accepted."
|
||||
else
|
||||
if git config --get-regexp alias | grep -o -q "\.${corecommand} "; then
|
||||
echo "Alias ${corecommand} accepted."
|
||||
echo 1>&2 "Alias ${corecommand} accepted."
|
||||
else
|
||||
usage && echo "error: unknown GIT command: $corecommand" && exit 1
|
||||
usage && echo 1>&2 "error: unknown GIT command: $corecommand" && exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# check if workspace name is registered
|
||||
function checkWSName () {
|
||||
while read workspace; do
|
||||
checkWSName () {
|
||||
while read -r workspace; do
|
||||
parseWsName "$workspace"
|
||||
if [[ $rwsname == "$wsname" ]]; then return; fi
|
||||
done <<< "$(echo "$(listall)")"
|
||||
done <<< "$(listall)"
|
||||
# when here the ws name was not found
|
||||
usage && echo "error: unknown workspace name: $wsname" && exit 1
|
||||
usage && echo 1>&2 "error: unknown workspace name: $wsname" && exit 1
|
||||
}
|
||||
|
||||
# parse out wsname from workspacespec
|
||||
function parseWsName () {
|
||||
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
|
||||
function wsnameToCurrent () {
|
||||
while read workspace; do
|
||||
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 <<< "$(echo "$(listall)")"
|
||||
done <<< "$(listall)"
|
||||
# when here then not in workspace dir
|
||||
echo "error: you are not in a workspace directory. your registered workspaces are:" && \
|
||||
wslist="$(echo "$(listall)")" && echo "${wslist:-'<no workspaces defined yet>'}" && exit 1
|
||||
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
|
||||
function allowedargcount () {
|
||||
( test "$paramcount" -ne "$1" ) && ( usage && echo 1>&2 "error: wrong number of arguments" && 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
|
||||
function executBulkOp () {
|
||||
executBulkOp () {
|
||||
checkGitCommand
|
||||
if ! $allwsmode && ! $singlemode; then wsnameToCurrent; fi # by default git bulk works within the 'current' workspace
|
||||
listall | while read workspacespec; do
|
||||
listall | while read -r workspacespec; do
|
||||
parseWsName "$workspacespec"
|
||||
if [[ -n $wsname ]] && [[ $rwsname != "$wsname" ]]; then continue; fi
|
||||
eval cd "\"$rwsdir\""
|
||||
local actual=$(pwd)
|
||||
echo "Executing bulk operation in workspace ${invers}$actual${reset}"
|
||||
eval find -L . -name ".git" | while read line; do
|
||||
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
|
||||
eval cd "\"$gitrepodir\"" # into git repo location
|
||||
local curdir=$(pwd)
|
||||
local leadingpath=${curdir#${actual}}
|
||||
echo "Current repository: ${leadingpath%/*}/${bldred}${curdir##*/}${reset}"
|
||||
guardedExecution
|
||||
eval cd "\"$rwsdir\"" # back to origin location of last find command
|
||||
done
|
||||
done
|
||||
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="${#}"
|
||||
|
|
@ -129,22 +190,27 @@ 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" && break ;;
|
||||
-a)
|
||||
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)
|
||||
-g)
|
||||
guardedmode=true ;;
|
||||
-w)
|
||||
-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 ;;
|
||||
butilcommand="executBulkOp" && corecommand="$1" && gitcommand="$*" && break ;;
|
||||
esac && shift
|
||||
done
|
||||
|
||||
|
|
@ -152,13 +218,14 @@ done
|
|||
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 "Selected single workspace mode in workspace: $wsname" && checkWSName; fi
|
||||
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;;
|
||||
addworkspace) allowedargcount 3 5;;
|
||||
esac
|
||||
|
||||
$butilcommand # run user command
|
||||
# pass the origin arguments to the 'executBulkOp'
|
||||
$butilcommand "$@" # run user command
|
||||
|
|
|
|||
|
|
@ -9,6 +9,15 @@ GIT_MERGELOG_FORMAT="$(git config changelog.mergeformat)"
|
|||
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]
|
||||
|
|
@ -146,6 +155,8 @@ _fetchCommitRange() {
|
|||
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
|
||||
|
|
@ -233,7 +244,7 @@ commitList() {
|
|||
# fetch our tags
|
||||
local _ref _date _tag _tab='%x09'
|
||||
local _tag_regex='tag: *'
|
||||
while IFS=$'\t' read _ref _date _tag; do
|
||||
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.
|
||||
|
|
@ -280,7 +291,8 @@ commitList() {
|
|||
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="$(_valueForKeyFakeAssocArray "${__curr_tag}" "${tags_list[*]}")"
|
||||
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
|
||||
|
|
@ -375,8 +387,8 @@ _exit() {
|
|||
# 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 fileds.
|
||||
pid_list=( $(ps -f |
|
||||
# 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
|
||||
}
|
||||
|
|
@ -391,7 +403,7 @@ _exit() {
|
|||
local _pid
|
||||
for _pid in "${pid_list[@]}"; do
|
||||
echo "killing: ${_pid}"
|
||||
kill -TERM ${_pid}
|
||||
kill -TERM "${_pid}"
|
||||
done
|
||||
|
||||
wait; stty sane; exit 1
|
||||
|
|
@ -474,10 +486,10 @@ main() {
|
|||
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[*]}")"
|
||||
|
||||
|
|
@ -487,7 +499,6 @@ main() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
start_commit="$start_commit"
|
||||
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!"
|
||||
|
|
@ -529,9 +540,10 @@ main() {
|
|||
#
|
||||
# generate changelog
|
||||
#
|
||||
local tmpfile="$(git_extra_mktemp)"
|
||||
local changelog="$(_valueForKeyFakeAssocArray "output_file" "${option[*]}")"
|
||||
local title_tag="$(_valueForKeyFakeAssocArray "title_tag" "${option[*]}")"
|
||||
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
|
||||
|
|
@ -550,7 +562,7 @@ main() {
|
|||
fi
|
||||
|
||||
if [[ -z "$changelog" ]]; then
|
||||
changelog="$(ls | egrep 'change|history' -i | head -n1)"
|
||||
changelog="$(find . -mindepth 1 -maxdepth 1 \( -iname '*change*' -o -iname '*history*' \) | head -n1)"
|
||||
if [[ -z "$changelog" ]]; then
|
||||
changelog="History.md";
|
||||
fi
|
||||
|
|
@ -569,12 +581,11 @@ main() {
|
|||
else
|
||||
cp -f "$tmpfile" "$changelog"
|
||||
rm -f "$tmpfile"
|
||||
# Use `eval` to handle GIT_EDITOR which contains space and options,
|
||||
# like ""C:\Program Files (x86)\Notepad++\notepad++.exe" -multiInst ".
|
||||
# Thanks @JanSchulz to inspire me this solution
|
||||
[[ -n "$GIT_EDITOR" ]] && eval $GIT_EDITOR "$changelog"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
_exit
|
||||
|
||||
if [[ -n "$GIT_EDITOR" ]]; then
|
||||
git_editor "$changelog" || _exit
|
||||
else
|
||||
less "$changelog" || _exit
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ALIAS=chore
|
||||
git feature -a $ALIAS "$@"
|
||||
|
|
@ -1,7 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
PROGNAME="git-clear"
|
||||
FORCE=0
|
||||
|
||||
echo -n "Sure? - This command may delete files that cannot be recovered, including those in .gitignore [y/N]: "
|
||||
read ans
|
||||
if [ "$ans" == "y" ]
|
||||
then git clean -d -f -x && git reset --hard
|
||||
_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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/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 ans
|
||||
if [ "$ans" == "y" ]
|
||||
read -r answer
|
||||
if [ "$answer" = "y" ]
|
||||
then git clean -d -f && git reset --hard
|
||||
fi
|
||||
|
|
|
|||
17
bin/git-coauthor
Executable file
17
bin/git-coauthor
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/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
|
||||
|
|
@ -1,6 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SINCE="last week"
|
||||
test $# -ne 0 && SINCE=$@
|
||||
echo "... commits since $SINCE" >&2
|
||||
git log --pretty='%an - %s' --after="@{$SINCE}"
|
||||
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
|
||||
|
|
|
|||
1
bin/git-continue
Symbolic link
1
bin/git-continue
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
git-abort
|
||||
|
|
@ -4,4 +4,4 @@ user="$*"
|
|||
|
||||
test -z "$user" && echo "user name required." 1>&2 && exit 1
|
||||
|
||||
git shortlog --author="$user"
|
||||
git shortlog --format=format:"%h %s" --author="$user"
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ if test "$1" = "--all"; then
|
|||
echo
|
||||
fi
|
||||
|
||||
echo total `git rev-list --count HEAD`
|
||||
echo total "$(git rev-list --count HEAD)"
|
||||
|
|
|
|||
78
bin/git-cp
Executable file
78
bin/git-cp
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
#!/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
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
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`
|
||||
REMOTE_PREF=$(git config git-extras.create-branch.remote)
|
||||
if [ -n "$REMOTE_PREF" ]; then
|
||||
REMOTE=$REMOTE_PREF
|
||||
fi
|
||||
|
|
@ -20,6 +20,12 @@ do
|
|||
REMOTE=origin
|
||||
fi
|
||||
;;
|
||||
--from)
|
||||
if [[ -n $2 ]]; then
|
||||
START_POINT=$2
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
BRANCH=$1
|
||||
esac
|
||||
|
|
@ -33,19 +39,26 @@ then
|
|||
REMOTE=origin
|
||||
fi
|
||||
|
||||
test -z $BRANCH && echo "branch argument required." 1>&2 && exit 1
|
||||
test -z "$BRANCH" && echo "branch argument required." 1>&2 && exit 1
|
||||
|
||||
if [[ -n $REMOTE ]]
|
||||
then
|
||||
git ls-remote --exit-code $REMOTE 1>/dev/null 2>/tmp/ls-remote-error
|
||||
stderr=$(git_extra_mktemp)
|
||||
git ls-remote --exit-code "$REMOTE" 1>/dev/null 2>"$stderr"
|
||||
REMOTE_EXIT=$?
|
||||
REMOTE_ERROR=$(</tmp/ls-remote-error)
|
||||
rm -f /tmp/ls-remote-error
|
||||
REMOTE_ERROR=$(<"$stderr")
|
||||
rm -f "$stderr"
|
||||
if [ $REMOTE_EXIT -eq 0 ]
|
||||
then
|
||||
git push $REMOTE HEAD:refs/heads/$BRANCH
|
||||
git fetch $REMOTE
|
||||
git checkout --track -b $BRANCH $REMOTE/$BRANCH
|
||||
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
|
||||
|
|
@ -55,4 +68,9 @@ then
|
|||
fi
|
||||
fi
|
||||
|
||||
git checkout -b $BRANCH
|
||||
if [[ -n $START_POINT ]]
|
||||
then
|
||||
git checkout -b "$BRANCH" "$START_POINT"
|
||||
else
|
||||
git checkout -b "$BRANCH"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
set -e
|
||||
|
||||
# Assert there is at least one branch provided
|
||||
test -z $1 && echo "branch required." 1>&2 && exit 1
|
||||
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")
|
||||
remote=$(git config "branch.$branch.remote" || echo "origin")
|
||||
ref=$(git config "branch.$branch.merge" || echo "refs/heads/$branch")
|
||||
|
||||
git branch -D $branch || true
|
||||
git branch -D "$branch" || true
|
||||
# Avoid deleting local upstream
|
||||
[ "$remote" == "." ] && continue
|
||||
git branch -d -r $remote/$branch || continue
|
||||
git push $remote :$ref
|
||||
[ "$remote" = "." ] && continue
|
||||
git branch -d -r "$remote/$branch" || continue
|
||||
git push "$remote" ":$ref"
|
||||
done
|
||||
|
|
|
|||
60
bin/git-delete-gone-branches
Executable file
60
bin/git-delete-gone-branches
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
dry_run=false
|
||||
force=false
|
||||
prune=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--dry-run)
|
||||
dry_run=true
|
||||
shift
|
||||
;;
|
||||
-f|--force)
|
||||
force=true
|
||||
shift
|
||||
;;
|
||||
-p|--prune)
|
||||
prune=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Usage: git delete-gone-branches [-n|--dry-run] [-f|--force] [-p|--prune]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$prune" = true ]; then
|
||||
git fetch --prune
|
||||
fi
|
||||
|
||||
gone_branches=$(git for-each-ref --format \
|
||||
'%(if:equals=gone)%(upstream:track,nobracket)%(then)%(refname:short)%(end)' refs/heads/ | sed '/^$/d')
|
||||
|
||||
if [ -z "$gone_branches" ]; then
|
||||
echo "No branches with a gone remote found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$dry_run" = true ]; then
|
||||
echo "Would delete the following branches:"
|
||||
echo "$gone_branches"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "The following branches will be deleted:"
|
||||
echo "$gone_branches"
|
||||
|
||||
if [ "$force" = false ]; then
|
||||
read -r -p "Delete these branches? [y/N] " confirm
|
||||
if [[ ! "$confirm" =~ ^[yY]$ ]]; then
|
||||
echo "Aborted."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$gone_branches" | xargs git branch -D
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
branches=$(git branch --no-color --merged | grep -v "\*" | grep -v master | grep -v svn)
|
||||
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
|
||||
echo "$branches" | xargs git branch -d
|
||||
fi
|
||||
|
|
|
|||
28
bin/git-delete-squashed-branches
Executable file
28
bin/git-delete-squashed-branches
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/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
|
||||
|
|
@ -1,24 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
test -z "$1" && echo "submodule required" 1>&2 && exit 1
|
||||
cd "$(git root)"
|
||||
test ! -f .gitmodules && echo ".gitmodules file not found" 1>&2 && exit 2
|
||||
abort() {
|
||||
error="$1" && shift
|
||||
echo "ERROR: $*" 1>&2
|
||||
test -z "$FORCE" && exit "$error"
|
||||
}
|
||||
|
||||
NAME="$(echo "$1" | sed 's/\/$//g')"
|
||||
test -z \
|
||||
"$(git config --file=.gitmodules submodule."$NAME".url)" \
|
||||
&& echo "submodule not found" 1>&2 && exit 3
|
||||
# Don't abort on failures. This allows to cleanup after a previous failure.
|
||||
[ "$1" = '--force' ] && FORCE=1 && shift
|
||||
|
||||
# 1. Delete the relevant section from .git/config and clean submodule files
|
||||
git submodule deinit -f "$NAME" || exit 4
|
||||
rmdir "$NAME"
|
||||
rm -rf .git/modules/"$NAME"
|
||||
# 2. Delete the relevant line from .gitmodules
|
||||
git config --file=.gitmodules --remove-section submodule."$NAME"
|
||||
git add .gitmodules
|
||||
# 3. Run git rm --cached path_to_submodule
|
||||
git rm --cached -rf "$NAME"
|
||||
# 4. Need to confirm and commit the changes for yourself
|
||||
echo
|
||||
echo "Now submodule $NAME is deleted."
|
||||
echo 'Confirm with `git submodule status` and commit the changes for yourself.'
|
||||
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.'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Assert there is at least one tag provided
|
||||
test -z $1 && echo "tag required." 1>&2 && exit 1
|
||||
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=""
|
||||
|
|
@ -13,5 +22,7 @@ do
|
|||
done
|
||||
|
||||
# Delete all the tags
|
||||
# shellcheck disable=SC2086
|
||||
git tag -d $local_tags
|
||||
git push origin $origin_refs
|
||||
# shellcheck disable=SC2086
|
||||
git push "$origin" $origin_refs
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
branch=master
|
||||
branch=$(git_extra_default_branch)
|
||||
filter=ACM
|
||||
|
||||
if test $# -eq 1; then
|
||||
|
|
@ -12,4 +12,4 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
git diff --name-only --diff-filter=$filter $branch
|
||||
git diff --name-only --diff-filter="$filter" "$branch"
|
||||
104
bin/git-effort
104
bin/git-effort
|
|
@ -59,14 +59,14 @@ active_days() {
|
|||
|
||||
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
|
||||
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
|
||||
|
|
@ -84,37 +84,38 @@ effort() {
|
|||
local color reset_color commits len dot f_dot i msg active
|
||||
reset_color=""
|
||||
test "$to_tty" = true && reset_color="$(tputq sgr0)"
|
||||
commit_dates=`dates "$path"`
|
||||
[ $? -gt 0 ] && exit 255
|
||||
if ! commit_dates=$(dates "$path"); then
|
||||
exit 255
|
||||
fi
|
||||
|
||||
# Ensure it's not just an empty line
|
||||
if [ -z "`head -c 1 <<<$(echo $commit_dates)`" ]
|
||||
if [ -z "$(head -c 1 <<<"$commit_dates")" ]
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
commits=`wc -l <<<"$(echo "$commit_dates")"`
|
||||
commits=$(wc -l <<<"$commit_dates")
|
||||
color='90'
|
||||
|
||||
# ignore <= --above
|
||||
test $commits -le $above && exit 0
|
||||
test "$commits" -le "$above" && exit 0
|
||||
|
||||
# commits
|
||||
color_for $(( $commits - $above ))
|
||||
color_for $(( commits - above ))
|
||||
len=${#path}
|
||||
dot="."
|
||||
f_dot="$path"
|
||||
i=0 ; while test $i -lt $(( $columns - $len )) ; do
|
||||
i=0 ; while test $i -lt $(( columns - len )) ; do
|
||||
f_dot=$f_dot$dot
|
||||
i=$(($i+1))
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
msg=$(printf " ${color}%s %-10d" "$f_dot" $commits)
|
||||
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)"
|
||||
active=$(active_days "$commit_dates")
|
||||
color_for $(( active - above ))
|
||||
msg="$msg $(printf "${color} %d${reset_color}\n" "$active")"
|
||||
echo "$msg"
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +137,16 @@ sort_effort() {
|
|||
clear
|
||||
echo " "
|
||||
heading
|
||||
< $tmp sort -rn -k 2
|
||||
< "$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=()
|
||||
|
|
@ -177,50 +187,48 @@ fi
|
|||
args_to_git_log="${args_to_git_log#\ \'\'}"
|
||||
export args_to_git_log
|
||||
|
||||
# set column width to match longest filename
|
||||
columns=$(( $(git ls-files | awk '{ print length }' | sort -rn | head -1 ) + 5 ))
|
||||
export columns
|
||||
|
||||
# [path ...]
|
||||
|
||||
if test "${#paths}" -eq 0; then
|
||||
save_ifs=$IFS
|
||||
IFS=`echo -en "\n\b"`
|
||||
paths=(`git ls-files`)
|
||||
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
|
||||
|
||||
# export functions so subshells can call them
|
||||
export -f effort
|
||||
export -f color_for
|
||||
export -f active_days
|
||||
export -f dates
|
||||
export -f tputq
|
||||
export to_tty
|
||||
export above
|
||||
export log_args
|
||||
|
||||
|
||||
bash_params=
|
||||
# If bash exits successfully with --import-functions,
|
||||
# then we need to pass it (FreeBSD probably)
|
||||
bash --import-functions -c ":" 1>/dev/null 2>&1
|
||||
if [ $? -eq 0 ] ; then
|
||||
bash_params="--import-functions"
|
||||
fi
|
||||
|
||||
heading
|
||||
|
||||
# send paths to effort
|
||||
printf "%s\0" "${paths[@]}" | xargs -0 -n 1 -P 4 -I % bash $bash_params -c "effort \"%\"" | tee $tmp
|
||||
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
|
||||
test "$(wc -l "$tmp" | awk '{print $1}')" -gt 1 && sort_effort
|
||||
echo
|
||||
|
||||
show_cursor_and_cleanup
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
VERSION="5.0.0"
|
||||
INSTALL_SCRIPT="https://raw.githubusercontent.com/tj/git-extras/master/install.sh"
|
||||
VERSION="7.6.0-dev"
|
||||
INSTALL_SCRIPT="https://raw.githubusercontent.com/tj/git-extras/main/install.sh"
|
||||
|
||||
update() {
|
||||
local bin="$(which git-extras)"
|
||||
local bin="$(command -v git-extras)"
|
||||
local prefix=${bin%/*/*}
|
||||
local orig=$PWD
|
||||
|
||||
|
|
@ -14,10 +14,10 @@ update() {
|
|||
}
|
||||
|
||||
updateForWindows() {
|
||||
local bin="$(which git-extras)"
|
||||
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 \
|
||||
|
|
|
|||
136
bin/git-feature
136
bin/git-feature
|
|
@ -1,55 +1,105 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
branch_prefix=feature
|
||||
branch_prefix=$(git config --get git-extras.feature.prefix)
|
||||
|
||||
if [ -z "$branch_prefix" ]; then
|
||||
branch_prefix="feature"
|
||||
fi
|
||||
|
||||
branch_separator=$(git config --get git-extras.feature.separator)
|
||||
|
||||
if [ -z "$branch_separator" ]; then
|
||||
branch_separator="/"
|
||||
fi
|
||||
|
||||
merge_mode="--no-ff"
|
||||
finish=false
|
||||
declare -a argv
|
||||
while test $# != 0
|
||||
do
|
||||
case $1 in
|
||||
-a|--alias )
|
||||
if [[ -n $2 ]]
|
||||
then
|
||||
shift # shift -a|-alias
|
||||
branch_prefix=$1
|
||||
else
|
||||
argv+=($1) # treat tail '-a' as <name>
|
||||
fi
|
||||
;;
|
||||
-r|--remote )
|
||||
if [[ -n $2 ]]
|
||||
then
|
||||
remote=$2
|
||||
shift
|
||||
else
|
||||
remote="origin"
|
||||
fi
|
||||
;;
|
||||
* )
|
||||
argv+=($1)
|
||||
;;
|
||||
esac
|
||||
case $1 in
|
||||
-a|--alias )
|
||||
if [[ -n $2 ]] && [[ $2 != -- ]]
|
||||
then
|
||||
shift # shift -a|-alias
|
||||
branch_prefix=$1
|
||||
else
|
||||
echo >&2 "option $1 requires a value"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
-r|--remote )
|
||||
if [[ -n $2 ]] && [[ $2 != -- ]]
|
||||
then
|
||||
remote=$2
|
||||
shift
|
||||
else
|
||||
remote="origin"
|
||||
fi
|
||||
;;
|
||||
-s|--separator )
|
||||
if [[ -n $2 ]] && [[ $2 != -- ]]
|
||||
then
|
||||
branch_separator=$2
|
||||
shift
|
||||
else
|
||||
echo >&2 "option $1 requires a value"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--squash )
|
||||
merge_mode="--squash"
|
||||
;;
|
||||
--from )
|
||||
start_point=$2
|
||||
shift
|
||||
;;
|
||||
-- )
|
||||
# terminate argument parsing
|
||||
shift
|
||||
argv+=("$@")
|
||||
break
|
||||
;;
|
||||
finish )
|
||||
finish=true
|
||||
;;
|
||||
* )
|
||||
argv+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
concatargs(){
|
||||
str=$(IFS='-'; echo "$*")
|
||||
branch="$branch_prefix"/$str
|
||||
concatargs() {
|
||||
str=$(IFS='-'; echo "$*")
|
||||
branch="$branch_prefix$branch_separator$str"
|
||||
}
|
||||
|
||||
if test "${argv[0]}" = "finish"; then
|
||||
test -z "${argv[1]}" && echo "$branch_prefix" "<name> required." 1>&2 && exit 1
|
||||
branch="$branch_prefix"/"${argv[1]}"
|
||||
git merge --no-ff "$branch" && git delete-branch "$branch"
|
||||
test -z "${argv[0]}" && echo "$branch_prefix" "<name> required." 1>&2 && exit 1
|
||||
|
||||
concatargs "${argv[@]}"
|
||||
|
||||
if "${finish}"
|
||||
then
|
||||
git merge ${merge_mode} "$branch" && git delete-branch "$branch"
|
||||
else
|
||||
test -z "${argv[0]}" && echo "$branch_prefix" "<name> required." 1>&2 && exit 1
|
||||
if test -n "${argv[1]}"; then
|
||||
concatargs "${argv[@]}"
|
||||
else
|
||||
branch="$branch_prefix"/"${argv[0]}"
|
||||
fi
|
||||
if [[ -n $remote ]]
|
||||
then
|
||||
git create-branch -r $remote $branch
|
||||
else
|
||||
git create-branch $branch
|
||||
fi
|
||||
if [[ -n $remote ]] && [[ -z $start_point ]]
|
||||
then
|
||||
git create-branch -r "$remote" "$branch"
|
||||
fi
|
||||
|
||||
if [[ -z $remote ]] && [[ -z $start_point ]]
|
||||
then
|
||||
git create-branch "$branch"
|
||||
fi
|
||||
|
||||
if [[ -n $remote ]] && [[ -n $start_point ]]
|
||||
then
|
||||
git create-branch -r "$remote" --from "$start_point" "$branch"
|
||||
fi
|
||||
|
||||
if [[ -z $remote ]] && [[ -n $start_point ]]
|
||||
then
|
||||
git create-branch --from "$start_point" "$branch"
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ repository from scratch.
|
|||
changed files will be reset, local branches and other remotes will be removed.
|
||||
|
||||
OPTIONS:
|
||||
-b, --branch The branch to pull from the remote (default: master)
|
||||
-b, --branch The branch to pull from the remote
|
||||
-h, --help Display this help message
|
||||
"
|
||||
}
|
||||
|
|
@ -63,21 +63,21 @@ main() {
|
|||
|
||||
if [ -d "${destination_path}/.git" ]; then
|
||||
(
|
||||
cd ${destination_path}
|
||||
cd "${destination_path}"
|
||||
|
||||
# Delete all remotes
|
||||
for remote in `git remote`; do
|
||||
git remote rm ${remote}
|
||||
for remote in $(git remote); do
|
||||
git remote rm "${remote}"
|
||||
done
|
||||
|
||||
# Add origin
|
||||
git remote add origin ${remote_url}
|
||||
git remote add origin "${remote_url}"
|
||||
git fetch origin
|
||||
|
||||
# Set default branch
|
||||
if [ -z "${branch:-}" ]; then
|
||||
branch=`LC_ALL=C git remote show origin | grep -oP '(?<=HEAD branch: )[^ ]+$'`
|
||||
git remote set-head origin ${branch}
|
||||
branch=$(LC_ALL=C git remote show origin | grep -oP '(?<=HEAD branch: )[^ ]+$')
|
||||
git remote set-head origin "${branch}"
|
||||
else
|
||||
git remote set-head origin -a
|
||||
fi
|
||||
|
|
@ -87,19 +87,20 @@ main() {
|
|||
git reset --hard HEAD
|
||||
|
||||
# Get on the desired branch
|
||||
git checkout ${branch}
|
||||
git reset --hard origin/${branch}
|
||||
git checkout "${branch}"
|
||||
git reset --hard "origin/${branch}"
|
||||
|
||||
# Delete all other branches
|
||||
branches=`git branch | grep -v \* | xargs`
|
||||
# shellcheck disable=SC2063
|
||||
branches=$(git branch | grep -v '*' | xargs)
|
||||
if [ -n "${branches}" ]; then
|
||||
git branch -D ${branches}
|
||||
git branch -D "${branches}"
|
||||
fi
|
||||
)
|
||||
elif [ -n "${branch:-}" ]; then
|
||||
git clone -b ${branch} ${remote_url} ${destination_path}
|
||||
git clone -b "${branch}" "${remote_url}" "${destination_path}"
|
||||
else
|
||||
git clone ${remote_url} ${destination_path}
|
||||
git clone "${remote_url}" "${destination_path}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
29
bin/git-fork
29
bin/git-fork
|
|
@ -12,16 +12,18 @@ test -z "$url" && abort "github repo needs to be specified as an argument"
|
|||
|
||||
# validate user
|
||||
echo "Enter your github username"
|
||||
read user
|
||||
read -r user
|
||||
[ -n "$user" ] || abort "git username required"
|
||||
echo "Enter github password for user \"$user\""
|
||||
read -s passwd
|
||||
echo "Enter github two-factor authentication code (leave blank if not set up)"
|
||||
read MFA_CODE
|
||||
# personal access token
|
||||
# config name is github-personal-access-token '_' is not allowed in git config
|
||||
|
||||
github_personal_access_token=$(git config --default "$GITHUB_TOKEN" git-extras.github-personal-access-token)
|
||||
|
||||
test -z "$github_personal_access_token" && abort "GITHUB_TOKEN, or git config git-extras.github-personal-access-token required"
|
||||
|
||||
# extract owner + project from repo url
|
||||
project=${url##*/}
|
||||
owner=${url%/$project}
|
||||
owner=${url%/"$project"}
|
||||
project=${project%.git}
|
||||
if [[ $owner == git@* ]]; then
|
||||
owner=${owner##*:}
|
||||
|
|
@ -30,19 +32,20 @@ else
|
|||
fi
|
||||
|
||||
# validate
|
||||
[ -z "$project" -o -z "$owner" ] && abort "github repo needs to be specified as an argument"
|
||||
[[ -z "$project" || -z "$owner" ]] && abort "github repo needs to be specified as an argument"
|
||||
|
||||
# create fork
|
||||
curl -qsf \
|
||||
if ! curl -qsf \
|
||||
-X POST \
|
||||
-u "$user:$passwd" \
|
||||
-u "$user:$github_personal_access_token" \
|
||||
-H "X-GitHub-OTP: $MFA_CODE" \
|
||||
"https://api.github.com/repos/$owner/$project/forks"
|
||||
|
||||
[ $? = 0 ] || abort "fork failed"
|
||||
then
|
||||
abort "fork failed"
|
||||
fi
|
||||
|
||||
echo "Add GitHub remote branch via SSH (you will be prompted to verify the server's credentials)? (y/n)"
|
||||
read use_ssh
|
||||
read -r use_ssh
|
||||
# Check if user has ssh configured with GitHub
|
||||
if [ -n "$use_ssh" ] && ssh -T git@github.com 2>&1 | grep -qi 'success'; then
|
||||
remote_prefix="git@github.com:"
|
||||
|
|
@ -58,7 +61,7 @@ else
|
|||
# clone forked repo into current dir
|
||||
git clone "${remote_prefix}${user}/${project}.git" "$project"
|
||||
# add reference to origin fork so can merge in upstream changes
|
||||
cd "$project"
|
||||
cd "$project" || exit
|
||||
git remote add upstream "${remote_prefix}${owner}/${project}.git"
|
||||
git fetch upstream
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -2,19 +2,19 @@
|
|||
|
||||
branch=$1
|
||||
|
||||
test -z $branch && echo "branch required." 1>&2 && exit 1
|
||||
test -z "$branch" && echo "branch required." 1>&2 && exit 1
|
||||
|
||||
changes=`git status --porcelain`
|
||||
changes=$(git status --porcelain)
|
||||
|
||||
clean()
|
||||
{
|
||||
git symbolic-ref HEAD refs/heads/$branch
|
||||
git symbolic-ref HEAD "refs/heads/$branch"
|
||||
rm .git/index
|
||||
git clean -fdx
|
||||
}
|
||||
|
||||
if [ ! -z "$changes" ]; then
|
||||
read -p "All untracked changes will be lost. Continue [y/N]? " res
|
||||
if [ -n "$changes" ]; then
|
||||
read -rp "All untracked changes will be lost. Continue [y/N]? " res
|
||||
case $res in
|
||||
[Yy]* ) ;;
|
||||
* ) exit 0;;
|
||||
|
|
|
|||
40
bin/git-get
Executable file
40
bin/git-get
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
_usage() {
|
||||
printf '%s\n' "usage: ${0##*/} <url>
|
||||
usage: ${0##*/} --help
|
||||
|
||||
Clone a repository in a particular directory."
|
||||
}
|
||||
|
||||
if (( $# == 0 )); then
|
||||
_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for arg; do
|
||||
if [ "$arg" = '-h' ] || [ "$arg" = '--help' ]; then
|
||||
_usage
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
url=$1
|
||||
if ! shift; then
|
||||
printf 'ERROR: Failed to shift' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
clone_path=$(git config --get git-extras.get.clone-path)
|
||||
|
||||
if [ -z "$clone_path" ]; then
|
||||
printf 'ERROR: %s\n' "Git configuration key 'git-extras.get.clone-path' must be set to a directory to clone under" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dirname=${url%/}
|
||||
dirname=${dirname%.git}
|
||||
dirname=${dirname##*/}
|
||||
|
||||
mkdir -p "$clone_path"
|
||||
git clone "$url" "$clone_path/$dirname" "$@"
|
||||
|
|
@ -4,10 +4,10 @@ echo 'setting up gh-pages'
|
|||
echo '-------------------'
|
||||
|
||||
echo 'Tell me your github account username: '
|
||||
read username
|
||||
read -r username
|
||||
|
||||
echo 'Now, tell me your repository name: '
|
||||
read repository
|
||||
read -r repository
|
||||
|
||||
git stash \
|
||||
&& git checkout -b 'gh-pages' \
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
src=$1
|
||||
dst=$2
|
||||
|
||||
test -z $src && echo "source branch required." 1>&2 && exit 1
|
||||
test -z $dst && echo "destination branch required." 1>&2 && exit 1
|
||||
test -z "$src" && echo "source branch required." 1>&2 && exit 1
|
||||
test -z "$dst" && echo "destination branch required." 1>&2 && exit 1
|
||||
|
||||
git checkout $dst \
|
||||
&& git merge --no-ff $src \
|
||||
&& git branch -d $src
|
||||
git checkout "$dst" \
|
||||
&& git merge --no-ff "$src" \
|
||||
&& git branch -d "$src"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
for param in $*
|
||||
for param in "$@"
|
||||
do
|
||||
case $param in
|
||||
-h)
|
||||
|
|
@ -31,7 +31,7 @@ do
|
|||
esac
|
||||
done
|
||||
|
||||
cd "$(git-root)" # cd for git blame
|
||||
cd "$(git-root)" || exit # cd for git blame
|
||||
MERGED_LOG=$(git_extra_mktemp)
|
||||
if [[ $EMAIL == '-e' ]]
|
||||
then
|
||||
|
|
@ -44,11 +44,13 @@ for file in $(git diff --name-only "$@")
|
|||
do
|
||||
test -n "$DEBUG" && echo "git blame $file"
|
||||
# $1 - since $2 - until
|
||||
git blame $NOT_WHITESPACE --line-porcelain "$1" -- "$file" 2> /dev/null |
|
||||
LC_ALL=C sed -n "$PATTERN" | sort | uniq -c | LC_ALL=C sed 's/^\(.\)/- \1/' >> $MERGED_LOG
|
||||
# shellcheck disable=SC2086
|
||||
git blame $NOT_WHITESPACE --line-porcelain "$1" -- "$file" 2> /dev/null |
|
||||
LC_ALL=C sed -n "$PATTERN" | sort | uniq -c | LC_ALL=C sed 's/^\(.\)/- \1/' >> "$MERGED_LOG"
|
||||
# if $2 not given, use current commit as "until"
|
||||
# shellcheck disable=SC2086
|
||||
git blame $NOT_WHITESPACE --line-porcelain "${2-@}" -- "$file" 2> /dev/null |
|
||||
LC_ALL=C sed -n "$PATTERN" | sort | uniq -c | LC_ALL=C sed 's/^\(.\)/+ \1/' >> $MERGED_LOG
|
||||
LC_ALL=C sed -n "$PATTERN" | sort | uniq -c | LC_ALL=C sed 's/^\(.\)/+ \1/' >> "$MERGED_LOG"
|
||||
done
|
||||
|
||||
DEBUG="$DEBUG" awk '
|
||||
|
|
@ -71,8 +73,8 @@ END {
|
|||
printf("%d %s\n", contributors[people], people)
|
||||
}
|
||||
}
|
||||
}' $MERGED_LOG | sort -nr | # only gawk supports built-in sort function
|
||||
while read line
|
||||
}' "$MERGED_LOG" | sort -nr | # only gawk supports built-in sort function
|
||||
while read -r line
|
||||
do
|
||||
people=${line#* }
|
||||
num=${line%% *}
|
||||
|
|
@ -87,7 +89,7 @@ do
|
|||
do
|
||||
printf "+"
|
||||
done
|
||||
printf "(%s)" $num
|
||||
printf "(%s)" "$num"
|
||||
else
|
||||
for (( i = 0; i < num; i++ ))
|
||||
do
|
||||
|
|
@ -103,7 +105,7 @@ do
|
|||
do
|
||||
printf "-"
|
||||
done
|
||||
printf "(%s)" $num
|
||||
printf "(%s)" "$num"
|
||||
else
|
||||
for (( i = 0; i > num; i-- ))
|
||||
do
|
||||
|
|
|
|||
274
bin/git-ignore
274
bin/git-ignore
|
|
@ -1,6 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
function show_contents {
|
||||
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
|
||||
|
||||
# awk script that takes 2 input files. The first one is newline deilmeted
|
||||
# string of patterns to look for, second one is the file to remove them from.
|
||||
# outfile has to be passed with -v upon call and is the file result is
|
||||
# written to.
|
||||
read -r -d '' AWK_SCRIPT <<'EOF'
|
||||
# process the first "file" (newline split argument list)
|
||||
NR==FNR { a[b++]=$0; next; }
|
||||
# process file
|
||||
{
|
||||
found=0;
|
||||
for (i=0; i != b; i++) {
|
||||
if (a[i] == $0) { found=1; }
|
||||
}
|
||||
if (found == 1) { print "... removing '"$0"'"; }
|
||||
else { print $0 > outfile }
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
|
||||
show_contents() {
|
||||
local file="${2/#~/$HOME}"
|
||||
if [ -f "$file" ]; then
|
||||
echo "$1 gitignore: $2" && cat "$file"
|
||||
|
|
@ -9,52 +31,149 @@ function show_contents {
|
|||
fi
|
||||
}
|
||||
|
||||
function show_global {
|
||||
show_contents Global `git config --global core.excludesfile`
|
||||
cd_to_git_root() {
|
||||
local error_level="$1"
|
||||
|
||||
if ! git rev-parse --git-dir &>/dev/null; then
|
||||
if [ "$error_level" = '--warn' ]; then
|
||||
echo "Warning: Not currently in a Git repository" >&2
|
||||
elif [ "$error_level" = '--error' ]; then
|
||||
echo "Error: Not currently in a Git repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local result=
|
||||
if result=$(git rev-parse --show-toplevel 2>/dev/null); then
|
||||
cd "$result" || exit
|
||||
fi
|
||||
}
|
||||
|
||||
function add_global {
|
||||
local global_gitignore=$(git config --global core.excludesfile)
|
||||
global_ignore() {
|
||||
if ! git config --global core.excludesFile 2>/dev/null; then
|
||||
if [ -f "$HOME/.gitignore" ]; then
|
||||
echo "$HOME/.gitignore"
|
||||
else
|
||||
echo "${XDG_CONFIG_HOME:-$HOME/.config}/git/ignore"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
show_global() {
|
||||
show_contents Global "$(global_ignore)"
|
||||
}
|
||||
|
||||
add_global() {
|
||||
local global_gitignore
|
||||
global_gitignore="$(global_ignore)"
|
||||
if [ -z "$global_gitignore" ]; then
|
||||
echo "Can't find global .gitignore."
|
||||
echo ""
|
||||
echo "Use 'git config --global --add core.excludesfile ~/.gitignore-global' to set the path to your global gitignore file to '~/.gitignore-global'."
|
||||
echo ""
|
||||
else
|
||||
add_patterns `git config --global core.excludesfile` "$@"
|
||||
add_patterns "$global_gitignore" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function show_local {
|
||||
cd "$(git root)"
|
||||
show_local() {
|
||||
cd_to_git_root --warn
|
||||
show_contents Local .gitignore
|
||||
}
|
||||
|
||||
function add_local {
|
||||
cd "$(git root)"
|
||||
add_local() {
|
||||
cd_to_git_root --warn
|
||||
add_patterns .gitignore "$@"
|
||||
}
|
||||
|
||||
function show_private {
|
||||
cd "$(git root)"
|
||||
show_contents Private .git/info/exclude
|
||||
show_private() {
|
||||
cd_to_git_root --error
|
||||
show_contents Private "${GIT_DIR}/info/exclude"
|
||||
}
|
||||
|
||||
function add_private {
|
||||
cd "$(git root)"
|
||||
test -d .git/info || mkdir -p .git/info
|
||||
add_patterns .git/info/exclude "$@"
|
||||
add_private() {
|
||||
cd_to_git_root --error
|
||||
test -d "${GIT_DIR}/info" || mkdir -p "${GIT_DIR}/info"
|
||||
add_patterns "${GIT_DIR}/info/exclude" "$@"
|
||||
}
|
||||
|
||||
function add_patterns {
|
||||
add_patterns() {
|
||||
echo "Adding pattern(s) to: $1"
|
||||
local file="${1/#~/$HOME}"
|
||||
dir_name=$(dirname "$file")
|
||||
if [ ! -d "$dir_name" ]; then
|
||||
mkdir -p "$dir_name"
|
||||
fi
|
||||
if [ -s "$file" ]; then
|
||||
# If the content of $file doesn't end with a newline, add one
|
||||
test "$(tail -c 1 "$file")" != "" && echo "" >> "$file"
|
||||
fi
|
||||
for pattern in "${@:2}"; do
|
||||
echo "... adding '$pattern'"
|
||||
(test -f "$file" && test "$pattern" && grep -q -F -x -- "$pattern" "$file") || echo "$pattern" >> "$file"
|
||||
done
|
||||
}
|
||||
|
||||
edit_file() {
|
||||
local file="${2/#~/$HOME}"
|
||||
if [ -f "$file" ]; then
|
||||
echo "Editing $1 gitignore: ($2)" && eval "$(git var GIT_EDITOR) $(printf '%q' "$file")"
|
||||
echo "Done."
|
||||
else
|
||||
echo "There is no $1 .gitignore yet." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
_usage() {
|
||||
cat << EOF
|
||||
Usage: git ignore [OPTION]... [PATTERN]...
|
||||
Modify or display local global or private gitignore files.
|
||||
|
||||
OPTIONs set context (local, global, private) and action (display, add,
|
||||
remove, edit). In case of collision, last flag overwrites preceding ones.
|
||||
Defaults are: local context, action is display (see man git ignore for
|
||||
more details).
|
||||
Context examples:
|
||||
local: .../repo/.gitignore
|
||||
private: .../repo/.git/info/exclude
|
||||
global: \$HOME/.gitignore
|
||||
|
||||
PATTERNs are the gitignore patterns as specified in git documentation.
|
||||
|
||||
Options:
|
||||
-l, --local Set context to local gitignore
|
||||
-g, --global Set context to global gitignore
|
||||
-p, --private Set context to private gitignore
|
||||
-e, --edit Set action to edit
|
||||
-r, --remove Set action to remove
|
||||
-h, --help Print this message
|
||||
-- End of options delimiter
|
||||
EOF
|
||||
}
|
||||
|
||||
remove_patterns() {
|
||||
declare -a args
|
||||
local tmpfile
|
||||
args=( "${@:3}" )
|
||||
local file="${2/#~/$HOME}"
|
||||
if [ -f "$file" ]; then
|
||||
tmpfile="$(mktemp -q "${TMPDIR:-/tmp}"/git-extras-ignore.XXXXXX 2>/dev/null)"
|
||||
echo "Removing patterns from $1 gitignore: $2"
|
||||
awk -v outfile="$tmpfile" "${AWK_SCRIPT}"\
|
||||
<(printf '%s\n' "${args[@]}") "$file"
|
||||
cat "$tmpfile" > "$file"
|
||||
rm "$tmpfile"
|
||||
else
|
||||
echo "There is no $1 .gitignore yet"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# can have only 1 action and 1 level, if conflicting flags are passed
|
||||
# latter ones overwrite former
|
||||
# sanity of args not tested (e.g. there should be no args if -e is supplied)
|
||||
if test $# -eq 0; then
|
||||
show_global
|
||||
echo "---------------------------------"
|
||||
|
|
@ -62,22 +181,105 @@ if test $# -eq 0; then
|
|||
echo "---------------------------------"
|
||||
show_private
|
||||
else
|
||||
case "$1" in
|
||||
-l|--local)
|
||||
test $# -gt 1 && add_local "${@:2}" && echo
|
||||
show_local
|
||||
;;
|
||||
-g|--global)
|
||||
test $# -gt 1 && add_global "${@:2}" && echo
|
||||
show_global
|
||||
;;
|
||||
-p|--private)
|
||||
test $# -gt 1 && add_private "${@:2}" && echo
|
||||
show_private
|
||||
;;
|
||||
*)
|
||||
add_local "$@"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# parse flags and args
|
||||
level="none"
|
||||
action="none"
|
||||
declare -a args
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
_usage
|
||||
exit 0
|
||||
;;
|
||||
-l|--local)
|
||||
level="local"
|
||||
;;
|
||||
-g|--global)
|
||||
level="global"
|
||||
;;
|
||||
-p|--private)
|
||||
level="private"
|
||||
;;
|
||||
-e|--edit)
|
||||
action="edit"
|
||||
;;
|
||||
-r|--remove)
|
||||
action="remove"
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
args+=("$@")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
args+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
# compatible with previous version
|
||||
if [ "$action" = "none" ]; then
|
||||
case "$level" in
|
||||
local)
|
||||
test ${#args[@]} -ne 0 && add_local "${args[@]}" && echo
|
||||
show_local
|
||||
;;
|
||||
global)
|
||||
test ${#args[@]} -ne 0 && add_global "${args[@]}" && echo
|
||||
show_global
|
||||
;;
|
||||
private)
|
||||
test ${#args[@]} -ne 0 && add_private "${args[@]}" && echo
|
||||
show_private
|
||||
;;
|
||||
none)
|
||||
add_local "${args[@]}"
|
||||
# maybe show_local here too?
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
# open file in editor
|
||||
elif [ "$action" = "edit" ]; then
|
||||
case "$level" in
|
||||
local|none)
|
||||
cd_to_git_root --warn
|
||||
edit_file 'local' .gitignore && echo
|
||||
;;
|
||||
global)
|
||||
global_gitignore="$(global_ignore)"
|
||||
edit_file global "$global_gitignore" && echo
|
||||
;;
|
||||
private)
|
||||
cd_to_git_root --error
|
||||
test -d "${GIT_DIR}/info" || mkdir -p "${GIT_DIR}/info"
|
||||
edit_file private "${GIT_DIR}/info/exclude" && echo
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
# remove entries
|
||||
else
|
||||
if [ ${#args[@]} -eq 0 ]; then
|
||||
echo "Nothing to remove."
|
||||
exit 0
|
||||
fi
|
||||
case "$level" in
|
||||
local|none)
|
||||
cd_to_git_root --warn
|
||||
remove_patterns 'local' .gitignore "${args[@]}" && echo
|
||||
show_local
|
||||
;;
|
||||
global)
|
||||
global_gitignore="$(global_ignore)"
|
||||
remove_patterns global "$global_gitignore" "${args[@]}" && echo
|
||||
show_global
|
||||
;;
|
||||
private)
|
||||
cd_to_git_root --error
|
||||
remove_patterns private "${GIT_DIR}/info/exclude" "${args[@]}" && echo
|
||||
show_private
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
gitignore_io_url="https://www.gitignore.io/api/"
|
||||
gitignore_io_url="https://www.toptal.com/developers/gitignore/api/"
|
||||
default_path="$HOME/.gi_list"
|
||||
if [[ -n "$XDG_CACHE_HOME" ]]; then
|
||||
default_path="$XDG_CACHE_HOME/git-extras/gi_list"
|
||||
mkdir -p "$XDG_CACHE_HOME/git-extras"
|
||||
fi
|
||||
|
||||
update_gi_list() {
|
||||
curl -L -s "${gitignore_io_url}/list" > ~/.gi_list
|
||||
curl -L -s "${gitignore_io_url}/list" > "$default_path"
|
||||
}
|
||||
|
||||
print_in_alphabetical_order() {
|
||||
|
|
@ -13,7 +17,7 @@ print_in_alphabetical_order() {
|
|||
for ignorable in $(echo "$gi_list" | sort);
|
||||
do
|
||||
first_character=${ignorable:0:1}
|
||||
if [[ $first_character = $previous_first_character ]]; then
|
||||
if [[ $first_character = "$previous_first_character" ]]; then
|
||||
printf " %s" "$ignorable"
|
||||
elif [[ $first = true ]]; then
|
||||
previous_first_character=$first_character
|
||||
|
|
@ -42,12 +46,11 @@ search() {
|
|||
}
|
||||
|
||||
print_last_modified_time() {
|
||||
gi_list_date=$(stat -c "%y" "$default_path" 2> /dev/null)
|
||||
if [ "$?" -ne 0 ]; then
|
||||
gi_list_date=$(stat -f "%t%Sm" "$default_path" 2> /dev/null)
|
||||
if [ "$?" -ne 0 ]; then
|
||||
gi_list_date=$(date -r "$default_path" +%s 2> /dev/null)
|
||||
[ "$?" -ne 0 ] && gi_list_date=0
|
||||
if ! gi_list_date=$(stat -c "%y" "$default_path" 2> /dev/null); then
|
||||
if ! gi_list_date=$(stat -f "%t%Sm" "$default_path" 2> /dev/null); then
|
||||
if ! gi_list_date=$(date -r "$default_path" +%s 2> /dev/null); then
|
||||
gi_list_date=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo "Last update time: $gi_list_date"
|
||||
|
|
@ -73,15 +76,15 @@ show_usage() {
|
|||
echo " [-l|--list-in-table] Print available types in table format"
|
||||
echo " [-L|--list-alphabetically] Print available types in alphabetical order "
|
||||
echo " [-s|--search] <word> Search word in available types"
|
||||
echo " [-t|--show-update-time] Show the last modified time of ~/.gi_list (where the list of available types is stored)"
|
||||
echo " [-u|--update-list] Update ~/.gi_list"
|
||||
echo " [-t|--show-update-time] Show the last modified time of $default_path (where the list of available types is stored)"
|
||||
echo " [-u|--update-list] Update $default_path"
|
||||
}
|
||||
|
||||
|
||||
check_list_exist() {
|
||||
if ! [ -f "$default_path" ]; then
|
||||
echo "-----Initial gitignore.io list----"
|
||||
update_gi_list &
|
||||
update_gi_list
|
||||
echo "-----Save to $default_path-----"
|
||||
echo
|
||||
fi
|
||||
|
|
|
|||
60
bin/git-info
60
bin/git-info
|
|
@ -1,11 +1,40 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
GREEN="$(tput setaf 2)"
|
||||
NORMAL="$(tput sgr0)"
|
||||
if [ "$1" = "--color" ] || [ "$2" = "--color" ] || \
|
||||
[ "$1" = "-c" ] || [ "$2" = "-c" ] ; then
|
||||
COLOR_TITLE="$GREEN"
|
||||
else
|
||||
COLOR_TITLE="$NORMAL"
|
||||
fi
|
||||
|
||||
HIDE_CONFIG=
|
||||
if [ "$1" != "--no-config" ] && [ "$2" != "--no-config" ]; then
|
||||
HIDE_CONFIG=1
|
||||
fi
|
||||
|
||||
get_config() {
|
||||
git config --list
|
||||
cmd_get_config="$(git config --get-all git-extras.info.config-grep)"
|
||||
if [ -z "$cmd_get_config" ]; then
|
||||
git config --list
|
||||
else
|
||||
eval "$cmd_get_config"
|
||||
fi
|
||||
}
|
||||
|
||||
most_recent_commit() {
|
||||
git log --max-count=1 --pretty=short
|
||||
cmd_get_log="$(git config --get-all git-extras.info.log)"
|
||||
if [ -z "$cmd_get_log" ]; then
|
||||
git log --max-count=1 --pretty=short
|
||||
else
|
||||
eval "$cmd_get_log"
|
||||
fi
|
||||
}
|
||||
|
||||
submodules() {
|
||||
# short sha1
|
||||
git submodule status | sed 's/\([^abcdef0-9]\{0,2\}\)\([abcdef0-9]\{7\}\)\([abcdef0-9]\{33\}\)\(.*\)/\1\2\4/'
|
||||
}
|
||||
|
||||
local_branches() {
|
||||
|
|
@ -21,27 +50,30 @@ remote_urls() {
|
|||
}
|
||||
|
||||
echon() {
|
||||
echo "$@"
|
||||
echo
|
||||
echo "$@"
|
||||
echo
|
||||
}
|
||||
|
||||
# Show info similar to svn
|
||||
|
||||
echo
|
||||
echon "## Remote URLs:"
|
||||
echon "${COLOR_TITLE}## Remote URLs:${NORMAL}"
|
||||
echon "$(remote_urls)"
|
||||
|
||||
echon "## Remote Branches:"
|
||||
echon "${COLOR_TITLE}## Remote Branches:${NORMAL}"
|
||||
echon "$(remote_branches)"
|
||||
|
||||
echon "## Local Branches:"
|
||||
echon "${COLOR_TITLE}## Local Branches:${NORMAL}"
|
||||
echon "$(local_branches)"
|
||||
|
||||
echon "## Most Recent Commit:"
|
||||
echon "$(most_recent_commit)"
|
||||
echon "Type 'git log' for more commits, or 'git show <commit id>' for full commit details."
|
||||
SUBMODULES_LOG=$(submodules)
|
||||
if [ -n "$SUBMODULES_LOG" ]; then
|
||||
echon "${COLOR_TITLE}## Submodule(s):${NORMAL}"
|
||||
echon "$SUBMODULES_LOG"
|
||||
fi
|
||||
|
||||
if test "$1" != "--no-config"; then
|
||||
echon "## Configuration (.git/config):"
|
||||
echon "${COLOR_TITLE}## Most Recent Commit:${NORMAL}"
|
||||
echon "$(most_recent_commit)"
|
||||
|
||||
if [ -n "$HIDE_CONFIG" ]; then
|
||||
echon "${COLOR_TITLE}## Configuration (.git/config):${NORMAL}"
|
||||
echon "$(get_config)"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ref=$(git symbolic-ref HEAD)
|
||||
branch=${ref#refs/heads/}
|
||||
|
||||
git log origin/${branch}..${branch} $*
|
||||
git log "@{upstream}..@" "$@"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
filename=$1
|
||||
test -z $filename && echo "filename required." 1>&2 && exit 1
|
||||
git update-index --skip-worktree $filename
|
||||
filename="$1"
|
||||
test -z "$filename" && echo "filename required." 1>&2 && exit 1
|
||||
git update-index --skip-worktree "$filename"
|
||||
|
|
|
|||
87
bin/git-magic
Executable file
87
bin/git-magic
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
# Bash unofficial strict mode
|
||||
set -eo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
USAGE='git-magic [-a] [-m msg] [-e] [-p] [-f]'
|
||||
|
||||
ALL=false
|
||||
PUSH=false
|
||||
FORCE=''
|
||||
ARGS=()
|
||||
|
||||
while getopts "m:eapfh" arg; do
|
||||
case "${arg}" in
|
||||
m)
|
||||
ARGS+=("-m")
|
||||
ARGS+=("${OPTARG}")
|
||||
;;
|
||||
e)
|
||||
ARGS+=("-e")
|
||||
;;
|
||||
a)
|
||||
ALL=true
|
||||
;;
|
||||
p)
|
||||
PUSH=true
|
||||
;;
|
||||
f)
|
||||
FORCE='--force-with-lease'
|
||||
;;
|
||||
h)
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
;;
|
||||
?)
|
||||
echo "${USAGE}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [[ $# != 0 ]]; then
|
||||
echo "Unknown arguments: $*"
|
||||
echo "${USAGE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -- "${ARGS[@]}" # restore positional parameters
|
||||
|
||||
if [[ $ALL == true ]]; then
|
||||
|
||||
# Check if there is no changes to stage
|
||||
if [[ -z $(git status --porcelain) ]]; then
|
||||
echo "No changes to commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get confirmation from user
|
||||
git status
|
||||
echo "Everything will be added"
|
||||
read -rp "Press enter to continue"
|
||||
|
||||
# Restore staging area so that, for example,
|
||||
# add and modify will not be separate entries in status
|
||||
git restore --staged . || true
|
||||
git add .
|
||||
fi
|
||||
|
||||
# Commit with generated message
|
||||
git commit --no-edit "$@" -m "$(git status --porcelain -uno)"
|
||||
|
||||
if [[ $PUSH == true ]]; then
|
||||
git push $FORCE
|
||||
fi
|
||||
|
||||
# --no-edit by default. use option -e to override this
|
||||
|
||||
# Arguments are passed with quoted "$@" to avoid misparsing
|
||||
|
||||
# Generated message comes after user provided arguments
|
||||
# so that user can insert title before it
|
||||
|
|
@ -9,7 +9,16 @@ usage() {
|
|||
}
|
||||
|
||||
cur_branch=$(current_branch)
|
||||
if [ "${!#}" == '--ff-only' ]; then
|
||||
|
||||
stashed=0
|
||||
if [ -n "$(git status --porcelain)" ];
|
||||
then
|
||||
echo "Local modifications detected, stashing"
|
||||
stashed=1
|
||||
git stash
|
||||
fi
|
||||
|
||||
if [ "${!#}" = '--ff-only' ]; then
|
||||
case $# in
|
||||
2 ) # dest --ff
|
||||
git push "$(git rev-parse --show-toplevel)" "$cur_branch":"$1";;
|
||||
|
|
@ -32,3 +41,8 @@ else
|
|||
usage
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ $stashed -eq 1 ];
|
||||
then
|
||||
git stash pop;
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ branch=$2
|
|||
prefix=$3
|
||||
flat=0
|
||||
|
||||
if test $prefix = "."; then
|
||||
if test "$prefix" = "."; then
|
||||
prefix=$(mktemp -u 'git-merge-repo.XXXXXXX')
|
||||
flat=1
|
||||
fi
|
||||
|
|
@ -16,10 +16,10 @@ message=$(git log -1 --pretty=%B)
|
|||
|
||||
if test $flat -eq 1; then
|
||||
git stash -u
|
||||
mv -i $prefix/* ./
|
||||
mv -i "$prefix"/* ./
|
||||
git undo
|
||||
git add .
|
||||
git commit -am "$message"
|
||||
git stash apply
|
||||
rm -drf $prefix
|
||||
rm -drf "$prefix"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
usage() {
|
||||
echo 1>&2 "usage: git missing [<first branch>] <second branch> [<git log options>]"
|
||||
echo 1>&2 "usage: git missing [<first branch>] <second branch> [<git log options>] [[--] <path>...]"
|
||||
}
|
||||
|
||||
if [ "${#}" -lt 1 ]
|
||||
|
|
@ -12,9 +12,20 @@ fi
|
|||
|
||||
declare -a git_log_args=()
|
||||
declare -a branches=()
|
||||
declare -a pathspec=()
|
||||
declare parse_path=false
|
||||
|
||||
for arg in "$@" ; do
|
||||
|
||||
if [[ $parse_path == true ]]; then
|
||||
pathspec+=("$@")
|
||||
break
|
||||
fi
|
||||
|
||||
case "$arg" in
|
||||
--)
|
||||
parse_path=true
|
||||
;;
|
||||
--*)
|
||||
git_log_args+=( "$arg" )
|
||||
;;
|
||||
|
|
@ -38,4 +49,4 @@ else
|
|||
exit 1
|
||||
fi
|
||||
|
||||
git log "${git_log_args[@]}" "$firstbranch"..."$secondbranch" --format="%m %h %s" --left-right
|
||||
git log "${git_log_args[@]}" "$firstbranch"..."$secondbranch" --format="%m %h %s" --left-right -- "${pathspec[@]}"
|
||||
|
|
|
|||
22
bin/git-mr
22
bin/git-mr
|
|
@ -7,22 +7,30 @@ if [ -z "${1-}" ] ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
remote_ref_kind=merge-requests
|
||||
|
||||
if test "$1" = "clean"; then
|
||||
git for-each-ref refs/heads/mr/* --format='%(refname)' | while read ref; do
|
||||
git branch -D ${ref#refs/heads/}
|
||||
git for-each-ref refs/heads/mr/* --format='%(refname)' | while read -r ref; do
|
||||
git branch -D "${ref#refs/heads/}"
|
||||
done
|
||||
exit 0
|
||||
elif [[ $1 =~ ^(https?://[^/]+/(.+))/merge_requests/([0-9]+).*$ ]]; then
|
||||
remote=${BASH_REMATCH[1]}.git
|
||||
id=${BASH_REMATCH[3]}
|
||||
elif [[ $1 =~ ^(https?://[^/]+/(.+))/pulls/([0-9]+).*$ ]]; then
|
||||
# Forgejo/Codeberg pull request URL, e.g.
|
||||
# https://codeberg.org/owner/repository/pulls/453
|
||||
remote=${BASH_REMATCH[1]}.git
|
||||
id=${BASH_REMATCH[3]}
|
||||
remote_ref_kind=pull
|
||||
else
|
||||
id=$1
|
||||
remote=${2:-origin}
|
||||
fi
|
||||
|
||||
branch=mr/$id
|
||||
remote_ref=refs/merge-requests/$id/head
|
||||
git fetch -fu $remote $remote_ref:$branch
|
||||
git checkout $branch
|
||||
git config --local --replace branch.$branch.merge $remote_ref
|
||||
git config --local --replace branch.$branch.remote $remote
|
||||
remote_ref=refs/$remote_ref_kind/$id/head
|
||||
git fetch -fu "$remote" "$remote_ref:$branch"
|
||||
git checkout "$branch"
|
||||
git config --local --replace "branch.$branch.merge" "$remote_ref"
|
||||
git config --local --replace "branch.$branch.remote" "$remote"
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@ do
|
|||
file="$file"' '"$i"
|
||||
shift
|
||||
done
|
||||
test -n "$*" && range="$*"
|
||||
test -n "$*" && range=("$@")
|
||||
|
||||
test -z "$file" && echo "file required." 1>&2 && exit 1
|
||||
if [ -z "$range" ]
|
||||
if [ -z "${range[*]}" ]
|
||||
then
|
||||
git filter-branch -f --index-filter "git rm -r --cached ""$file"" --ignore-unmatch" \
|
||||
--prune-empty --tag-name-filter cat -- --all
|
||||
else
|
||||
# don't quote $range so that we can forward multiple rev-list arguments
|
||||
# $range is an array so that we can forward multiple rev-list arguments
|
||||
git filter-branch -f --index-filter "git rm -r --cached ""$file"" --ignore-unmatch" \
|
||||
--prune-empty --tag-name-filter cat -- $range
|
||||
--prune-empty --tag-name-filter cat -- "${range[@]}"
|
||||
fi
|
||||
|
|
|
|||
11
bin/git-paste
Executable file
11
bin/git-paste
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if ! command -v pastebinit &>/dev/null; then
|
||||
echo >&2 "To run 'git paste', you need to install pastebinit in your system"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test $# -ne 0 || set -- '@{u}'
|
||||
git format-patch --stdout "$@" | pastebinit -f diff
|
||||
15
bin/git-pr
15
bin/git-pr
|
|
@ -12,10 +12,10 @@ pull() {
|
|||
ref="refs/pull/$id/merge"
|
||||
fi
|
||||
|
||||
git fetch -fu $remote $ref:$branch && \
|
||||
git checkout $branch && \
|
||||
git config --local --replace branch.$branch.merge $ref && \
|
||||
git config --local --replace branch.$branch.remote $remote;
|
||||
git fetch -fu "$remote" "$ref:$branch" && \
|
||||
git checkout "$branch" && \
|
||||
git config --local --replace "branch.$branch.merge" "$ref" && \
|
||||
git config --local --replace "branch.$branch.remote" "$remote"
|
||||
}
|
||||
|
||||
pull_pr_if_matched() {
|
||||
|
|
@ -54,12 +54,13 @@ done
|
|||
test -z "$1" && echo "pr number required." 1>&2 && exit 1
|
||||
|
||||
if test "$1" = "clean"; then
|
||||
git for-each-ref refs/heads/pr/* --format='%(refname)' | while read ref; do
|
||||
git branch -D ${ref#refs/heads/}
|
||||
git for-each-ref refs/heads/pr/* --format='%(refname)' | while read -r ref; do
|
||||
git branch -D "${ref#refs/heads/}"
|
||||
done
|
||||
|
||||
elif [[ "$1" =~ ^[0-9]+$ ]]; then
|
||||
remote=${2:-origin}
|
||||
remote_pref=${2:-$(git config --get git-extras.pr.remote)}
|
||||
remote=${remote_pref:-origin}
|
||||
id=$1
|
||||
branch=pr/$id
|
||||
pull "$remote" "$id" "$branch"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ SECONDARY_BRANCH=""
|
|||
FF="--ff"
|
||||
CONTINUE="no"
|
||||
|
||||
function current_branch() {
|
||||
current_branch() {
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
}
|
||||
|
||||
|
|
@ -19,10 +19,10 @@ function usage()
|
|||
echo " -c|--continue: Continue after the user updates conflicts."
|
||||
}
|
||||
|
||||
while [[ $# > 0 ]]
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
||||
|
||||
case $key in
|
||||
--no-ff)
|
||||
FF="--no-ff"
|
||||
|
|
@ -50,19 +50,17 @@ fi
|
|||
|
||||
if [[ "$CONTINUE" == "yes" ]]; then
|
||||
TARGET_BRANCH=$(current_branch)
|
||||
set $(echo "$TARGET_BRANCH" | sed -e "s/-rebased-on-top-of-/\n/g")
|
||||
if [[ $# != 2 ]]; then
|
||||
SECONDARY_BRANCH=${TARGET_BRANCH%"-rebased-on-top-of-"*}
|
||||
PRIMARY_BRANCH=${TARGET_BRANCH#*"-rebased-on-top-of-"}
|
||||
if [[ "${SECONDARY_BRANCH}-rebased-on-top-of-${PRIMARY_BRANCH}" != $TARGET_BRANCH ]]; then
|
||||
echo "Couldn't continue rebasing on ${TARGET_BRANCH}"
|
||||
exit 30 # Impossible to detect PRIMARY_BRANCH AND SECONDARY_BRANCH
|
||||
fi
|
||||
|
||||
SECONDARY_BRANCH=$1
|
||||
PRIMARY_BRANCH=$2
|
||||
|
||||
echo "Continuing rebasing of $SECONDARY_BRANCH on top of $PRIMARY_BRANCH"
|
||||
git commit || exit 51
|
||||
git branch -d ${SECONDARY_BRANCH} || exit 52
|
||||
git branch -m ${TARGET_BRANCH} ${SECONDARY_BRANCH} || exit 53
|
||||
git branch -d "${SECONDARY_BRANCH}" || exit 52
|
||||
git branch -m "${TARGET_BRANCH}" "${SECONDARY_BRANCH}" || exit 53
|
||||
|
||||
elif [[ "$PRIMARY_BRANCH" == "" ]]; then
|
||||
usage
|
||||
|
|
@ -71,14 +69,13 @@ else
|
|||
echo "Rebasing $SECONDARY_BRANCH on top of $PRIMARY_BRANCH"
|
||||
TARGET_BRANCH="${SECONDARY_BRANCH}-rebased-on-top-of-${PRIMARY_BRANCH}"
|
||||
|
||||
git checkout ${PRIMARY_BRANCH} || exit 41
|
||||
git checkout -b ${TARGET_BRANCH} || exit 42
|
||||
git merge ${SECONDARY_BRANCH} ${FF} \
|
||||
-m "Psycho-rebased branch ${SECONDARY_BRANCH} on top of ${PRIMARY_BRANCH}"
|
||||
git checkout "${PRIMARY_BRANCH}" || exit 41
|
||||
git checkout -b "${TARGET_BRANCH}" || exit 42
|
||||
|
||||
if [[ $? == 0 ]]; then
|
||||
git branch -d ${SECONDARY_BRANCH} || exit 43
|
||||
git branch -m ${TARGET_BRANCH} ${SECONDARY_BRANCH} || exit 44
|
||||
if git merge "${SECONDARY_BRANCH}" ${FF} \
|
||||
-m "Psycho-rebased branch ${SECONDARY_BRANCH} on top of ${PRIMARY_BRANCH}"; then
|
||||
git branch -d "${SECONDARY_BRANCH}" || exit 43
|
||||
git branch -m "${TARGET_BRANCH}" "${SECONDARY_BRANCH}" || exit 44
|
||||
else
|
||||
echo "Resolve the conflict and run ``${PROGRAM} --continue``."
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -28,15 +28,12 @@ json() {
|
|||
EOF
|
||||
}
|
||||
|
||||
# user
|
||||
# personal access token
|
||||
# config name is github-personal-access-token '_' is not allowed in git config
|
||||
|
||||
user=$(git config user.email)
|
||||
github_personal_access_token=$(git config --default "$GITHUB_TOKEN" git-extras.github-personal-access-token)
|
||||
|
||||
if [ -z "$user" ]; then
|
||||
user="$EMAIL"
|
||||
fi
|
||||
|
||||
test -z "$user" && abort "git config user.email required"
|
||||
test -z "$github_personal_access_token" && abort "GITHUB_TOKEN or git config git-extras.github-personal-access-token required"
|
||||
|
||||
# branch
|
||||
|
||||
|
|
@ -46,7 +43,7 @@ if [ -z "$remote" ]; then
|
|||
echo 'no upstream found, push to origin as default'
|
||||
remote="origin"
|
||||
fi
|
||||
[ "$remote" == "." ] && abort "the upstream should be a remote branch."
|
||||
[ "$remote" = "." ] && abort "the upstream should be a remote branch."
|
||||
|
||||
# make sure it's pushed
|
||||
|
||||
|
|
@ -67,7 +64,7 @@ echo " create pull-request for $project '$branch'"
|
|||
echo
|
||||
printf " title: " && read -r title
|
||||
printf " body: " && read -r body
|
||||
printf " base [master]: " && read -r base
|
||||
printf " base [%s]: " "$(git_extra_default_branch)" && read -r base
|
||||
printf " GitHub two-factor authentication code (leave blank if not set up): " && read -r mfa_code
|
||||
echo
|
||||
|
||||
|
|
@ -75,12 +72,14 @@ echo
|
|||
|
||||
if [ -z "$base" ]
|
||||
then
|
||||
base="master"
|
||||
base="$(git_extra_default_branch)"
|
||||
fi
|
||||
|
||||
body=$(json "$title" "$body" "$branch" "$base")
|
||||
|
||||
curl -u "$user" \
|
||||
-H "X-GitHub-OTP: $mfa_code" \
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token $github_personal_access_token" \
|
||||
-H "X-GitHub-OTP: $mfa_code" \
|
||||
"https://api.github.com/repos/$project/pulls" -d "$body"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,26 +17,26 @@ fi
|
|||
# Use a temporary index.
|
||||
index=$(git_extra_mktemp)
|
||||
cleanup() {
|
||||
rm $index
|
||||
rm "$index"
|
||||
exit 2
|
||||
}
|
||||
trap cleanup 2
|
||||
trap cleanup INT
|
||||
|
||||
# Go back in history while parent commits are available.
|
||||
echo "Trying to find a commit the patch applies to..."
|
||||
rev=$(git rev-parse HEAD)
|
||||
while [ $? = 0 ]
|
||||
do
|
||||
GIT_INDEX_FILE=$index git read-tree $rev
|
||||
GIT_INDEX_FILE=$index git read-tree "$rev"
|
||||
|
||||
# Try to apply the patch.
|
||||
GIT_INDEX_FILE=$index git apply --cached $1 >/dev/null 2>&1
|
||||
GIT_INDEX_FILE=$index git apply --cached "$1" &>/dev/null
|
||||
patch_failed=$?
|
||||
|
||||
# Do it again, but show the error, if the problem is the patch itself.
|
||||
if [ $patch_failed = 128 ]
|
||||
then
|
||||
GIT_INDEX_FILE=$index git apply --index --check $1
|
||||
GIT_INDEX_FILE=$index git apply --index --check "$1"
|
||||
exit $patch_failed
|
||||
fi
|
||||
|
||||
|
|
@ -45,19 +45,19 @@ do
|
|||
then
|
||||
# Manufacture a commit.
|
||||
tree=$(GIT_INDEX_FILE=$index git write-tree)
|
||||
commit=$(git commit-tree $tree -p $rev -m "$1")
|
||||
rm $index
|
||||
commit=$(git commit-tree "$tree" -p "$rev" -m "$1")
|
||||
rm "$index"
|
||||
|
||||
echo "Patch applied to $(git rev-parse --short $rev) as $(git rev-parse --short $commit)"
|
||||
echo "Patch applied to $(git rev-parse --short "$rev") as $(git rev-parse --short "$commit")"
|
||||
|
||||
git cherry-pick $commit
|
||||
git cherry-pick "$commit"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
rev=$(git rev-parse --verify -q $rev^)
|
||||
rev=$(git rev-parse --verify -q "$rev^")
|
||||
done
|
||||
|
||||
# No compatible commit found. Restore.
|
||||
echo "Failed to find a commit the patch applies to."
|
||||
rm $index
|
||||
rm "$index"
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
ALIAS=refactor
|
||||
git feature -a $ALIAS "$@"
|
||||
|
|
@ -4,17 +4,17 @@ set -e
|
|||
hook() {
|
||||
local hook=.git/hooks/$1.sh
|
||||
# compat without extname
|
||||
if test ! -f $hook; then
|
||||
if test ! -f "$hook"; then
|
||||
hook=.git/hooks/$1
|
||||
fi
|
||||
|
||||
if test -f $hook; then
|
||||
if test -f "$hook"; then
|
||||
echo "... $1"
|
||||
shift
|
||||
if test -x $hook; then
|
||||
if test -x "$hook"; then
|
||||
$hook "$@"
|
||||
else
|
||||
. $hook "$@"
|
||||
. "$hook" "$@"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
@ -34,12 +34,29 @@ if test $# -gt 0; then
|
|||
-c) need_changelog=true;;
|
||||
-r) remote=$2; shift ;;
|
||||
-m) msg=$2; shift ;;
|
||||
-s)
|
||||
test -n "$keyid" &&
|
||||
exit_with_msg "Please use '-s' OR '-u'"
|
||||
sign=true
|
||||
;;
|
||||
-u)
|
||||
test -n "$sign" &&
|
||||
exit_with_msg "Please use '-s' OR '-u'"
|
||||
keyid=$2
|
||||
shift
|
||||
;;
|
||||
--semver)
|
||||
test -z "$2" &&
|
||||
exit_with_msg "major/minor/patch required for --semver option"
|
||||
semver=$2
|
||||
shift
|
||||
;;
|
||||
--prefix)
|
||||
test -z "$2" &&
|
||||
exit_with_msg "prefix string required for --prefix option"
|
||||
prefix="$2"
|
||||
shift
|
||||
;;
|
||||
--no-empty-commit) no_empty_commit=true;;
|
||||
--) shift; hook_args="$hook_args $*"; break;;
|
||||
*) test -z "$version" && version=$1 ;;
|
||||
|
|
@ -58,7 +75,7 @@ if test $# -gt 0; then
|
|||
latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||
|
||||
if [[ ! "$latest_tag" =~ \
|
||||
^([^0-9]*)([1-9][0-9]+|[0-9])\.([1-9][0-9]+|[0-9])\.([1-9][0-9]+|[0-9])(.*) ]]; then
|
||||
^$prefix([^0-9]*)([1-9][0-9]+|[0-9])\.([1-9][0-9]+|[0-9])\.([1-9][0-9]+|[0-9])(.*) ]]; then
|
||||
echo "the latest tag doesn't match semver format requirement" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -75,9 +92,9 @@ if test $# -gt 0; then
|
|||
(( ++version ))
|
||||
|
||||
case "$semver" in
|
||||
major ) version="${BASH_REMATCH[1]}$version.0.0${BASH_REMATCH[5]}" ;;
|
||||
minor ) version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}.$version.0${BASH_REMATCH[5]}" ;;
|
||||
patch ) version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}.${BASH_REMATCH[3]}.$version${BASH_REMATCH[5]}" ;;
|
||||
major ) version="$prefix${BASH_REMATCH[1]}$version.0.0${BASH_REMATCH[5]}" ;;
|
||||
minor ) version="$prefix${BASH_REMATCH[1]}${BASH_REMATCH[2]}.$version.0${BASH_REMATCH[5]}" ;;
|
||||
patch ) version="$prefix${BASH_REMATCH[1]}${BASH_REMATCH[2]}.${BASH_REMATCH[3]}.$version${BASH_REMATCH[5]}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
|
@ -101,8 +118,17 @@ if test $# -gt 0; then
|
|||
git commit -a -m "$msg" --allow-empty
|
||||
fi
|
||||
|
||||
declare -a sign_args
|
||||
if [ "$sign" = true ]; then
|
||||
sign_args=("-s")
|
||||
fi
|
||||
|
||||
if [ -n "$keyid" ]; then
|
||||
sign_args=("-u" "$keyid")
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
git tag $version -a -m "$msg" \
|
||||
git tag "${sign_args[@]}" $version -a -m "$msg" \
|
||||
&& git push $remote --tags \
|
||||
&& git push $remote \
|
||||
&& hook post-release $hook_args \
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
set -e
|
||||
|
||||
# Assert there is at least one branch provided
|
||||
test -z $1 && echo "new branch name required." 1>&2 && exit 1
|
||||
test -z "$1" && echo "new branch name required." 1>&2 && exit 1
|
||||
|
||||
if [ -z $2 ]; then
|
||||
if [ -z "$2" ]; then
|
||||
new_branch="$1"
|
||||
old_branch="$(git symbolic-ref --short -q HEAD)"
|
||||
else
|
||||
|
|
|
|||
101
bin/git-rename-file
Executable file
101
bin/git-rename-file
Executable file
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Usage function
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: git rename-file [OPTIONS] <source> <destination>
|
||||
|
||||
Description:
|
||||
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.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit.
|
||||
|
||||
Examples:
|
||||
git rename-file old_filename new_filename
|
||||
git rename-file old_directory new_directory
|
||||
EOF
|
||||
}
|
||||
|
||||
# Check for help option
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for correct number of arguments
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Error: Incorrect number of arguments."
|
||||
echo ""
|
||||
usage >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign variables
|
||||
SOURCE="$1"
|
||||
DESTINATION="$2"
|
||||
TEMP_NAME="${SOURCE}.temp"
|
||||
|
||||
# Function to check if a file or directory exists in a case-sensitive manner
|
||||
check_case_sensitive_exists() {
|
||||
local path="$1"
|
||||
local dir
|
||||
local base
|
||||
|
||||
dir=$(dirname "$path")
|
||||
base=$(basename "$path")
|
||||
|
||||
if [ -e "$dir" ]; then
|
||||
if (cd "$dir" && find . -maxdepth 1 -name "$base" | grep -q "$base"); then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if source exists and is under version control
|
||||
if ! check_case_sensitive_exists "$SOURCE"; then
|
||||
echo "Error: Source '$SOURCE' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git ls-files --error-unmatch "$SOURCE" > /dev/null 2>&1; then
|
||||
echo "Error: Source '$SOURCE' is not under version control. If file or directory is new, it must at least be staged."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if destination already exists
|
||||
if check_case_sensitive_exists "$DESTINATION"; then
|
||||
echo "Error: Destination '$DESTINATION' already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the destination directory exists
|
||||
DEST_DIR=$(dirname "$DESTINATION")
|
||||
if ! check_case_sensitive_exists "$DEST_DIR"; then
|
||||
echo "Error: Destination directory '$DEST_DIR' does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create a rollback function
|
||||
rollback() {
|
||||
echo "Rolling back changes..."
|
||||
if [ -e "$TEMP_NAME" ]; then
|
||||
git mv -f "$TEMP_NAME" "$SOURCE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Trap errors to trigger rollback
|
||||
trap 'rollback' ERR
|
||||
|
||||
# Move the file to a temporary name within the Git repository
|
||||
git mv "$SOURCE" "$TEMP_NAME"
|
||||
|
||||
# Move the temporary file to the desired destination
|
||||
git mv "$TEMP_NAME" "$DESTINATION"
|
||||
|
||||
echo "Successfully renamed '$SOURCE' to '$DESTINATION'."
|
||||
|
|
@ -5,8 +5,8 @@ set -euo pipefail
|
|||
old=$1
|
||||
new=$2
|
||||
|
||||
test -z $old && echo "old remote name required." 1>&2 && exit 1
|
||||
test -z $new && echo "new remote name required." 1>&2 && exit 1
|
||||
test -z "$old" && echo "old remote name required." 1>&2 && exit 1
|
||||
test -z "$new" && echo "new remote name required." 1>&2 && exit 1
|
||||
|
||||
if ! git config --get "remote.$old.fetch" > /dev/null; then
|
||||
echo "remote $old doesn't exist"
|
||||
|
|
@ -14,7 +14,7 @@ if ! git config --get "remote.$old.fetch" > /dev/null; then
|
|||
fi
|
||||
|
||||
if git config --get "remote.$new.fetch" > /dev/null; then
|
||||
git remote remove $new
|
||||
git remote remove "$new"
|
||||
fi
|
||||
git remote rename $old $new
|
||||
git remote rename "$old $new"
|
||||
git remote -v
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
old=$1
|
||||
new=$2
|
||||
|
||||
test -z $old && echo "old tag name required." 1>&2 && exit 1
|
||||
test -z $new && echo "new tag name required." 1>&2 && exit 1
|
||||
test -z "$old" && echo "old tag name required." 1>&2 && exit 1
|
||||
test -z "$new" && echo "new tag name required." 1>&2 && exit 1
|
||||
|
||||
git tag $new $old
|
||||
git tag -d $old
|
||||
git push origin $new
|
||||
git push origin :refs/tags/$old
|
||||
git tag "$new" "$old"
|
||||
git tag -d "$old"
|
||||
git push origin "$new"
|
||||
git push origin ":refs/tags/$old"
|
||||
|
|
|
|||
82
bin/git-repl
82
bin/git-repl
|
|
@ -1,43 +1,99 @@
|
|||
#!/usr/bin/env bash
|
||||
shopt -s extglob
|
||||
|
||||
git version
|
||||
echo "git-extras version ""$(git-extras -v)"
|
||||
echo "type 'ls' to ls files below current directory, '!command' to execute any command or just 'subcommand' to execute any git subcommand"
|
||||
echo "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."
|
||||
|
||||
HISTIGNORE=${HISTIGNORE:-+([[:space:]])}
|
||||
HISTCONTROL=${HISTCONTROL:-ignoredups}
|
||||
use_local_history=$(git config --get --default 'false' git-extras.repl.use-local-history)
|
||||
if [[ "$use_local_history" == "true" ]]; then
|
||||
HISTFILE="$(git rev-parse --show-toplevel)/.git_extras_repl_history"
|
||||
else
|
||||
HISTFILE=${XDG_STATE_HOME:-$HOME/.local/state}/git_extras_repl_history
|
||||
fi
|
||||
|
||||
# file doesn't exist, is empty, or contains only whitespace
|
||||
if [[ ! -f "$HISTFILE" ]] || [[ ! -s "$HISTFILE" ]] || ! grep -q '[^[:space:]]' "$HISTFILE"; then
|
||||
# `history -r` .... `history -a` are not happy with an empty initial file in bash 3.2.57, which is what MacOS 26 ships with
|
||||
echo '!echo welcome to git-repl!' >> "$HISTFILE"
|
||||
fi
|
||||
history -r
|
||||
|
||||
while true; do
|
||||
# Current branch
|
||||
cur=`git symbolic-ref HEAD 2> /dev/null | cut -d/ -f3-`
|
||||
cur=$(git symbolic-ref HEAD 2> /dev/null | cut -d/ -f3-)
|
||||
|
||||
# Prompt
|
||||
if test -n "$cur"; then
|
||||
prompt="git ($cur)> "
|
||||
cur_string=" ($cur)"
|
||||
else
|
||||
prompt="git> "
|
||||
cur_string=""
|
||||
fi
|
||||
if test -n "$exit_status" && test "$exit_status" -ne 0; then
|
||||
es_string=$' \e[31m['"$exit_status"$']\e[0m'
|
||||
else
|
||||
es_string=""
|
||||
fi
|
||||
prompt_character=$(git config --get --default '>' git-extras.repl.prompt-character)
|
||||
|
||||
prefix=$(git config --get --default 'git' git-extras.repl.prefix)
|
||||
|
||||
show_project_name=$(git config --get --default 'false' git-extras.repl.show-project-name)
|
||||
if [[ "$show_project_name" == "true" ]]; then
|
||||
project_name=" $(basename "$(git rev-parse --show-toplevel)" .git)"
|
||||
else
|
||||
project_name=""
|
||||
fi
|
||||
|
||||
# Readline
|
||||
read -e -r -p "$prompt" cmd
|
||||
prompt_base="$prefix$project_name$cur_string$es_string$prompt_character"
|
||||
prompt_base_stripped=$(echo "$prompt_base" | awk '{$1=$1};1')
|
||||
prompt="$prompt_base_stripped "
|
||||
|
||||
# EOF
|
||||
test $? -ne 0 && break
|
||||
# Use arguments as a command if any are provided.
|
||||
if [ $# -ne 0 ]; then
|
||||
cmd=$*
|
||||
set --
|
||||
echo "$prompt" "$cmd" # It is as though you had entered a command.
|
||||
else
|
||||
# Readline
|
||||
read -e -r -p "$prompt" cmd
|
||||
# Check for EOF, and end the program if so (handles ^D).
|
||||
test $? -ne 0 && break
|
||||
fi
|
||||
|
||||
# History
|
||||
history -s "$cmd"
|
||||
# Add command to history if it is not all whitespace
|
||||
if [[ ! "$cmd" =~ ^[[:space:]]*$ ]]; then
|
||||
history -s "$cmd"
|
||||
fi
|
||||
|
||||
# Built-in commands
|
||||
case $cmd in
|
||||
ls) cmd=ls-files;;
|
||||
"") continue;;
|
||||
quit|exit) break;;
|
||||
"")
|
||||
on_enter_cmd=$(git config --get --default '' git-extras.repl.on-enter-command)
|
||||
if test -n "$on_enter_cmd"; then
|
||||
cmd="$on_enter_cmd"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
quit|exit|q) break;;
|
||||
esac
|
||||
|
||||
history -a
|
||||
|
||||
if [[ $cmd == !* ]]; then
|
||||
eval ${cmd:1}
|
||||
# shellcheck disable=SC2086
|
||||
eval ${cmd:1}
|
||||
elif [[ $cmd == git* ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
eval $cmd
|
||||
else
|
||||
eval git "$cmd"
|
||||
fi
|
||||
exit_status=$?
|
||||
done
|
||||
|
||||
echo
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ file="$1"
|
|||
commit="$2"
|
||||
|
||||
if [[ -f $file ]]; then
|
||||
git rm --cached -q -f -- $file
|
||||
if [[ -z $commit ]]; then
|
||||
git checkout HEAD -- $file
|
||||
git rm --cached -q -f -- "$file"
|
||||
if [[ -z $commit ]]; then
|
||||
git checkout HEAD -- "$file"
|
||||
echo "Reset '$1' to HEAD"
|
||||
else
|
||||
git checkout $commit -- $file
|
||||
git checkout "$commit" -- "$file"
|
||||
echo "Reset '$1' to $commit"
|
||||
fi
|
||||
else
|
||||
echo "File '$1' not found in `pwd`"
|
||||
else
|
||||
echo "File '$1' not found in $PWD"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@ git_root() {
|
|||
|
||||
# get the relative path of current path according to root of repo
|
||||
git_root_relative() {
|
||||
git rev-parse --show-prefix
|
||||
rel=$(git rev-parse --show-prefix)
|
||||
if [ -z "$rel" ]; then
|
||||
# git rev-parse --show-prefix will output empty string when we are in the root dir
|
||||
echo "."
|
||||
else
|
||||
echo "$rel"
|
||||
fi
|
||||
}
|
||||
|
||||
if test $# -eq 0; then
|
||||
|
|
|
|||
171
bin/git-scp
171
bin/git-scp
|
|
@ -18,7 +18,7 @@ function _test_git_scp()
|
|||
function set_remote()
|
||||
{
|
||||
remote=$1
|
||||
if [ $(git remote | grep -c -- ^$remote$) -eq 0 ]
|
||||
if [ "$(git remote | grep -c -- "^$remote$")" -eq 0 ]
|
||||
then
|
||||
COLOR_RED
|
||||
echo "Remote $remote does not exist in your git config"
|
||||
|
|
@ -39,8 +39,9 @@ function php_lint()
|
|||
test ! -f "$i" && continue
|
||||
case "$i" in
|
||||
*\.php|*\.phtml)
|
||||
php -l "$i" > /dev/null
|
||||
[ $? -gt 0 ] && error_count[${#error_count[@]}]="$i"
|
||||
if ! php -l "$i" > /dev/null; then
|
||||
error_count[${#error_count[@]}]="$i"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
|
@ -58,17 +59,17 @@ function php_lint()
|
|||
|
||||
function _dos2unix()
|
||||
{
|
||||
command -v dos2unix > /dev/null && dos2unix $@
|
||||
command -v dos2unix > /dev/null && dos2unix "$@"
|
||||
return 0
|
||||
}
|
||||
|
||||
function _sanitize()
|
||||
{
|
||||
git config --get-all extras.scp.sanitize | while read i
|
||||
git config --get-all extras.scp.sanitize | while read -r i
|
||||
do
|
||||
case $i in
|
||||
php_lint) php_lint $@;; # git config --global --add extras.scp.sanitize php_lint
|
||||
dos2unix) _dos2unix $@;; # git config --global --add extras.scp.sanitize dos2unix
|
||||
php_lint) php_lint "$@";; # git config --global --add extras.scp.sanitize php_lint
|
||||
dos2unix) _dos2unix "$@";; # git config --global --add extras.scp.sanitize dos2unix
|
||||
esac
|
||||
done
|
||||
return $?
|
||||
|
|
@ -76,14 +77,26 @@ function _sanitize()
|
|||
|
||||
function scp_and_stage
|
||||
{
|
||||
set_remote $1
|
||||
local verbose=0 interactive=0 dry_run=0
|
||||
while :
|
||||
do
|
||||
case "$1" in
|
||||
-v|--verbose) verbose=1; shift;;
|
||||
-i|--interactive) verbose=1; interactive=1; shift;;
|
||||
-n|--dry-run) verbose=1; dry_run=1; shift;;
|
||||
*) break;;
|
||||
esac
|
||||
done
|
||||
|
||||
set_remote "$1"
|
||||
shift
|
||||
|
||||
local refhead="$(git rev-parse --quiet --verify $1)"
|
||||
local refhead
|
||||
refhead="$(git rev-parse --quiet --verify "$1")"
|
||||
if [ -n "$refhead" ]
|
||||
then
|
||||
shift
|
||||
[ $(git branch --contains "$refhead" | grep -c '\*') -eq 0 ] &&
|
||||
[ "$(git branch --contains "$refhead" | grep -c '\*')" -eq 0 ] &&
|
||||
_error "refhead provided is not part of current branch"
|
||||
fi
|
||||
|
||||
|
|
@ -92,46 +105,117 @@ function scp_and_stage
|
|||
list=$(git ls-files "$@")" "$(git ls-files -o "$@")
|
||||
elif [ -n "$refhead" ]
|
||||
then
|
||||
git diff --stat $refhead
|
||||
list=$(git diff $refhead --name-only)
|
||||
[ "$verbose" -eq 1 ] && git --no-pager diff --stat "$refhead"
|
||||
list=$(git diff "$refhead" --name-only)
|
||||
else
|
||||
git diff
|
||||
[ "$verbose" -eq 1 ] && git --no-pager diff
|
||||
list=$(git diff --name-only)
|
||||
fi
|
||||
|
||||
deleted=$(for i in $list; do [ -f $i ] || echo $i; done)
|
||||
list=$(for i in $list; do [ -f $i ] && echo $i; done)
|
||||
deleted=$(for i in $list; do [ -f "$i" ] || echo "$i"; done)
|
||||
list=$(for i in $list; do [ -f "$i" ] && echo "$i"; done)
|
||||
|
||||
if [ "$interactive" -eq 1 ] && [ "$dry_run" -eq 0 ] && { [ -n "$list" ] || [ -n "$deleted" ]; }
|
||||
then
|
||||
local reply
|
||||
read -r -p "Proceed with sync to $remote? [y/N] " reply
|
||||
case "$reply" in
|
||||
y|Y|yes|YES) ;;
|
||||
*) _info "Aborted, nothing synced."; exit 0;;
|
||||
esac
|
||||
fi
|
||||
|
||||
local status=0
|
||||
|
||||
if [ -n "$list" ]
|
||||
then
|
||||
local _TMP=${0///}
|
||||
echo "$list" > $_TMP &&
|
||||
_sanitize $list &&
|
||||
_info Pushing to $remote \($(git config remote.$remote.url)\) &&
|
||||
rsync -rlDv --files-from=$_TMP ./ "$(git config remote.$remote.url)/" &&
|
||||
git add --force $list &&
|
||||
rm $_TMP
|
||||
# shellcheck disable=SC2086
|
||||
echo "$list" > "$_TMP"
|
||||
if [ "$dry_run" -eq 1 ] || _sanitize $list
|
||||
then
|
||||
_info "Pushing to $remote ($(git config "remote.$remote.url"))"
|
||||
if [ "$dry_run" -eq 1 ]
|
||||
then
|
||||
rsync -rlDvn --files-from="$_TMP" ./ "$(git config "remote.$remote.url")/"
|
||||
else
|
||||
rsync -rlDv --files-from="$_TMP" ./ "$(git config "remote.$remote.url")/" &&
|
||||
git add --force $list
|
||||
fi
|
||||
status=$?
|
||||
else
|
||||
status=1
|
||||
fi
|
||||
rm "$_TMP"
|
||||
fi
|
||||
|
||||
deleted=$(for i in $deleted; do echo $(git config remote.$remote.url | cut -d: -f2)/$i; done)
|
||||
deleted=$(for i in $deleted; do echo "$(git config "remote.$remote.url" | cut -d: -f2)/$i"; done)
|
||||
|
||||
[ -n "$deleted" ] &&
|
||||
COLOR_RED &&
|
||||
echo Deleted remote files &&
|
||||
ssh $(git config remote.$remote.url | cut -d: -f1) -t "rm $deleted" &&
|
||||
echo "$deleted"
|
||||
COLOR_RESET
|
||||
if [ -n "$deleted" ]
|
||||
then
|
||||
COLOR_RED
|
||||
echo Deleted remote files
|
||||
if [ "$dry_run" -eq 1 ]
|
||||
then
|
||||
echo "$deleted"
|
||||
else
|
||||
if ssh "$(git config "remote.$remote.url" | cut -d: -f1)" -t "rm $deleted"
|
||||
then
|
||||
echo "$deleted"
|
||||
else
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
COLOR_RESET
|
||||
fi
|
||||
|
||||
return "$status"
|
||||
}
|
||||
|
||||
function reverse_scp()
|
||||
{
|
||||
set_remote $1
|
||||
local verbose=0 interactive=0 dry_run=0
|
||||
while :
|
||||
do
|
||||
case "$1" in
|
||||
-v|--verbose) verbose=1; shift;;
|
||||
-i|--interactive) verbose=1; interactive=1; shift;;
|
||||
-n|--dry-run) verbose=1; dry_run=1; shift;;
|
||||
*) break;;
|
||||
esac
|
||||
done
|
||||
|
||||
set_remote "$1"
|
||||
shift
|
||||
|
||||
local _TMP=${0///}
|
||||
echo $@ > $_TMP &&
|
||||
rsync -rlDv --files-from=$_TMP "$(git config remote.$remote.url)/" ./ &&
|
||||
rm $_TMP
|
||||
echo "$@" > "$_TMP"
|
||||
|
||||
local status=0
|
||||
if [ "$verbose" -eq 1 ]
|
||||
then
|
||||
rsync -rlDvn --files-from="$_TMP" "$(git config "remote.$remote.url")/" ./
|
||||
status=$?
|
||||
fi
|
||||
|
||||
if [ "$dry_run" -eq 1 ]
|
||||
then
|
||||
rm "$_TMP"
|
||||
return "$status"
|
||||
fi
|
||||
|
||||
if [ "$interactive" -eq 1 ]
|
||||
then
|
||||
local reply
|
||||
read -r -p "Proceed with copy from $remote? [y/N] " reply
|
||||
case "$reply" in
|
||||
y|Y|yes|YES) ;;
|
||||
*) _info "Aborted, nothing copied."; rm "$_TMP"; exit 0;;
|
||||
esac
|
||||
fi
|
||||
|
||||
rsync -rlDv --files-from="$_TMP" "$(git config "remote.$remote.url")/" ./ &&
|
||||
rm "$_TMP"
|
||||
}
|
||||
|
||||
function _info()
|
||||
|
|
@ -145,13 +229,18 @@ function _usage()
|
|||
{
|
||||
echo "Usage:
|
||||
git scp -h|help|?
|
||||
git scp <remote> [ref|file..] # scp and stage your files to specified remote
|
||||
git scp <remote> [<ref>] # show diff relative to <ref> and upload unstaged files to <remote>
|
||||
git rscp <remote> [<file|directory>] # copy <remote> files to current working directory
|
||||
git scp [options] <remote> [ref|file..] # scp and stage your files to specified remote
|
||||
git scp [options] <remote> [<ref>] # show diff relative to <ref> and upload unstaged files to <remote>
|
||||
git rscp [options] <remote> [<file|directory>] # copy <remote> files to current working directory
|
||||
|
||||
OPTIONS:
|
||||
-v, --verbose print what will be synced before syncing
|
||||
-i, --interactive prompt for confirmation before syncing (implies --verbose)
|
||||
-n, --dry-run show what would be synced, change nothing (implies --verbose; no staging, no remote writes/deletes)
|
||||
"
|
||||
|
||||
case $1 in
|
||||
-v|verbose|--verbose) grep -A100 '^#* OPTIONS #*$' $0;;
|
||||
-v|verbose|--verbose) grep -A100 '^#* OPTIONS #*$' "$0" ;;
|
||||
esac
|
||||
exit
|
||||
}
|
||||
|
|
@ -161,18 +250,18 @@ function _error()
|
|||
[ $# -eq 0 ] && _usage && exit 0
|
||||
|
||||
echo
|
||||
echo ERROR: "$@"
|
||||
echo "ERROR: $*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
### OPTIONS ###
|
||||
case $(basename $0) in
|
||||
case $(basename "$0") in
|
||||
git-scp)
|
||||
case $1 in
|
||||
''|-h|'?'|help|--help) shift; _test_git_scp; _usage $@;;
|
||||
*) scp_and_stage $@;;
|
||||
''|-h|'?'|help|--help) shift; _test_git_scp; _usage "$@";;
|
||||
*) scp_and_stage "$@";;
|
||||
esac
|
||||
;;
|
||||
git-rscp) reverse_scp $@;;
|
||||
git-rscp) reverse_scp "$@";;
|
||||
esac
|
||||
|
|
|
|||
31
bin/git-sed
31
bin/git-sed
|
|
@ -16,7 +16,8 @@ do_commit() {
|
|||
true
|
||||
}
|
||||
|
||||
while [ "X$1" != "X" ]; do
|
||||
pathspec=
|
||||
while [ "$1" != "" ]; do
|
||||
case "$1" in
|
||||
-c|--commit)
|
||||
if git status --porcelain | grep .; then
|
||||
|
|
@ -32,7 +33,7 @@ actual command:
|
|||
}
|
||||
;;
|
||||
-f|--flags)
|
||||
if [ "X$2" = "X" ]; then
|
||||
if [ "$2" = "" ]; then
|
||||
usage
|
||||
echo "missing argument for $1"
|
||||
exit 1
|
||||
|
|
@ -44,17 +45,21 @@ actual command:
|
|||
usage
|
||||
exit
|
||||
;;
|
||||
--)
|
||||
pathspec="$*"
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
echo "unknown flag: $1"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ "X$search" = "X" ]; then
|
||||
if [ "$search" = "" ]; then
|
||||
search="$1"
|
||||
elif [ "X$replacement" = "X" ]; then
|
||||
elif [ "$replacement" = "" ]; then
|
||||
replacement="$1"
|
||||
elif [ "X$flags" = "X" ]; then
|
||||
elif [ "$flags" = "" ]; then
|
||||
flags="$1"
|
||||
else
|
||||
usage
|
||||
|
|
@ -70,9 +75,11 @@ all="$search$replacement$flags"
|
|||
case "$all" in
|
||||
*/*)
|
||||
ascii="$(for((i=32;i<=127;i++)) do printf '%b' "\\$(printf '%03o' "$i")"; done)"
|
||||
sep="$(printf '%s' "$ascii" | tr -d "$all")"
|
||||
escaped="${all//-/\\-}"
|
||||
escaped="${escaped//[/\\[}"
|
||||
sep="$(printf '%s' "$ascii" | tr -d "$escaped")"
|
||||
sep="$(printf %.1s "$sep")"
|
||||
if [ "X$sep" = "X" ] ; then
|
||||
if [ "$sep" = "" ] ; then
|
||||
echo 'could not find an unused character for sed separator character'
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -86,10 +93,12 @@ r=$(xargs -r false < /dev/null > /dev/null 2>&1 && echo r)
|
|||
need_bak=$(sed -i s/hello/world/ "$(git_extra_mktemp)" > /dev/null 2>&1 || echo true)
|
||||
|
||||
if [ "$need_bak" ]; then
|
||||
command="git grep -lz '$search' | xargs -0$r sed -i '' 's$sep$search$sep$replacement$sep$flags'"
|
||||
git grep -lz "$search" | xargs -0"$r" sed -i '' "s$sep$search$sep$replacement$sep$flags"
|
||||
command="git grep -lz '$search' $pathspec | xargs -0$r sed -i '' 's$sep$search$sep$replacement$sep$flags'"
|
||||
# shellcheck disable=SC2086
|
||||
git grep -lz "$search" $pathspec | xargs -0"$r" sed -i '' "s$sep$search$sep$replacement$sep$flags"
|
||||
else
|
||||
command="git grep -lz '$search' | xargs -0$r sed -i 's$sep$search$sep$replacement$sep$flags'"
|
||||
git grep -lz "$search" | xargs -0"$r" sed -i "s$sep$search$sep$replacement$sep$flags"
|
||||
command="git grep -lz '$search' $pathspec | xargs -0$r sed -i 's$sep$search$sep$replacement$sep$flags'"
|
||||
# shellcheck disable=SC2086
|
||||
git grep -lz "$search" $pathspec | xargs -0"$r" sed -i "s$sep$search$sep$replacement$sep$flags"
|
||||
fi
|
||||
do_commit
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
COMMIT_MESSAGE='Initial commit'
|
||||
|
||||
if [ "$1" == "-m" ]; then
|
||||
if [ "$1" = "-m" ]; then
|
||||
COMMIT_MESSAGE=$2
|
||||
shift; shift
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
git branch --no-color --merged | grep -v "\*" | grep -v master | tr -d ' '
|
||||
git branch --no-color --merged | grep -v "\*" | grep -v "$(git_extra_default_branch)" | tr -d ' '
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
git branch --no-color --no-merged | grep -v "\*" | grep -v master | tr -d ' '
|
||||
git branch --no-color --no-merged | grep -v "\*" | grep -v "$(git_extra_default_branch)" | tr -d ' '
|
||||
|
|
|
|||
|
|
@ -1,7 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
SQUASH_MSG=
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--squash-msg)
|
||||
SQUASH_MSG=1
|
||||
;;
|
||||
*)
|
||||
# set the argument back
|
||||
set -- "$@" "$arg"
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
src="$1"
|
||||
msg="$2"
|
||||
if [[ -n "$msg" ]] && [[ -n "$SQUASH_MSG" ]]; then
|
||||
>&2 echo "When commit message is given, --squash-msg is not allowed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
is_branch() {
|
||||
git show-ref --verify --quiet "refs/heads/$src"
|
||||
|
|
@ -12,7 +31,8 @@ is_commit_reference() {
|
|||
}
|
||||
|
||||
is_on_current_branch() {
|
||||
local commit_sha=`git rev-parse "$src"`
|
||||
local commit_sha
|
||||
commit_sha=$(git rev-parse "$src")
|
||||
git rev-list HEAD |
|
||||
grep -q -- "$commit_sha"
|
||||
}
|
||||
|
|
@ -23,8 +43,8 @@ commit_if_msg_provided() {
|
|||
fi
|
||||
}
|
||||
|
||||
prompt_continuation_if_squashing_master() {
|
||||
if [[ $src =~ ^master$ ]]; then
|
||||
prompt_continuation_if_squashing_default_branch() {
|
||||
if [[ $src == $(git_extra_default_branch) ]]; then
|
||||
read -p "Warning: squashing '$src'! Continue [y/N]? " -r
|
||||
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Exiting"
|
||||
|
|
@ -34,19 +54,26 @@ prompt_continuation_if_squashing_master() {
|
|||
}
|
||||
|
||||
squash_branch() {
|
||||
prompt_continuation_if_squashing_master
|
||||
prompt_continuation_if_squashing_default_branch
|
||||
if [ -n "$SQUASH_MSG" ]; then
|
||||
base=$(git merge-base "$src" @)
|
||||
msg=$(git log "$base".."$src" --format="%s%n%n%b" --no-merges --reverse)
|
||||
fi
|
||||
git merge --squash "$src" || exit 1 # quits if `git merge` fails
|
||||
commit_if_msg_provided
|
||||
}
|
||||
|
||||
squash_current_branch() {
|
||||
if [ -n "$SQUASH_MSG" ]; then
|
||||
msg=$(git log "$src"..@ --format="%s%n%n%b" --no-merges --reverse)
|
||||
fi
|
||||
git reset --soft "$src" || exit 1 # quits if `git reset` fails
|
||||
commit_if_msg_provided
|
||||
}
|
||||
|
||||
if `is_branch`; then
|
||||
if is_branch; then
|
||||
squash_branch
|
||||
elif `is_commit_reference` && `is_on_current_branch`; then
|
||||
elif is_commit_reference && is_on_current_branch; then
|
||||
squash_current_branch
|
||||
else
|
||||
echo "Source branch or commit reference required." 1>&2 && exit 1
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ EOF
|
|||
|
||||
error() {
|
||||
if [[ -n "$1" ]]; then
|
||||
local msg=$( echo "error: $1" )
|
||||
echo -e "${msg}" >&2
|
||||
echo "error: $1" >&2
|
||||
fi
|
||||
usage
|
||||
exit 1
|
||||
|
|
@ -34,7 +33,7 @@ stamp() {
|
|||
local commit_msg=$( git log -1 --pretty=%B )
|
||||
local stamp_msg
|
||||
[[ -n "${MSG}" ]] && stamp_msg="${ID} ${MSG}" || stamp_msg="${ID}"
|
||||
|
||||
|
||||
if ${REPLACE}; then
|
||||
# remove previous stamps with same ID from the commit message
|
||||
commit_msg=$(
|
||||
|
|
@ -71,9 +70,9 @@ parse_options() {
|
|||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
ID="$1"
|
||||
MSG="${@:2}"
|
||||
MSG="${*:2}"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
114
bin/git-standup
114
bin/git-standup
|
|
@ -5,17 +5,21 @@
|
|||
usage() {
|
||||
cat <<EOS
|
||||
Usage:
|
||||
git standup [-a <author name>] [-w <weekstart-weekend>] [-d <days-ago>] [-m <max-dir-depth>] [-g] [-h] [-f]
|
||||
git standup [-a <author name>] [-w <weekstart-weekend>|-d <days-ago>] [-m <max-dir-depth>] [-D date-format] [-L] [-h] [-f] [-B] [-n <number-of-commits] [-F <gpg|authordate>]
|
||||
|
||||
-a - Specify author to restrict search to
|
||||
-a - Specify author to restrict search to, default to current git user.
|
||||
Use "-a all" if you don't want the restriction.
|
||||
-w - Specify weekday range to limit search to
|
||||
-m - Specify the depth of recursive directory search
|
||||
-L - Toggle inclusion of symbolic links in recursive directory search
|
||||
-d - Specify the number of days back to include
|
||||
-D - Specify the date format for "git log" (default: relative)
|
||||
-h - Display this help screen
|
||||
-g - Show if commit is GPG signed (G) or not (N)
|
||||
-f - Fetch the latest commits beforehand
|
||||
-B - Display the commits in branch groups
|
||||
-n - Limit the number of commits displayed per group
|
||||
-F gpg - Show if commit is GPG signed (G) or not (N)
|
||||
-F authordate - Print author date instead of commit date
|
||||
|
||||
Examples:
|
||||
git standup -a "John Doe" -w "MON-FRI" -m 3
|
||||
|
|
@ -31,7 +35,7 @@ in_git_repo=$?
|
|||
|
||||
# Use colors, but only if connected to a terminal, and that terminal
|
||||
# supports them.
|
||||
if which tput >/dev/null 2>&1; then
|
||||
if command -v tput &>/dev/null; then
|
||||
ncolors=$(tput colors)
|
||||
fi
|
||||
if [[ -t 1 ]] && [[ -n "$ncolors" ]] && [[ "$ncolors" -ge 8 ]] ; then
|
||||
|
|
@ -60,7 +64,11 @@ fi
|
|||
# which may fail on systems lacking tput or terminfo
|
||||
set -e
|
||||
|
||||
while getopts "hgfd:a:w:m:D:L" opt; do
|
||||
RANGE_SPECIFIED=
|
||||
COMMIT_DATE_FORMAT=%cd
|
||||
USE_GPG_FORMAT=no
|
||||
|
||||
while getopts "hgfF:Bd:a:w:m:D:n:L" opt; do
|
||||
case $opt in
|
||||
h)
|
||||
usage
|
||||
|
|
@ -74,7 +82,8 @@ while getopts "hgfd:a:w:m:D:L" opt; do
|
|||
fi
|
||||
;;
|
||||
d)
|
||||
test -n "$SINCE" && warn "-d option is conflict with -w"
|
||||
test -n "$RANGE_SPECIFIED" && warn "-d option is conflict with -w"
|
||||
RANGE_SPECIFIED=yes
|
||||
if [ "$OPTARG" -lt 1 ]; then
|
||||
>&2 echo "Specify days less than one is invalid"
|
||||
exit 1
|
||||
|
|
@ -82,10 +91,11 @@ while getopts "hgfd:a:w:m:D:L" opt; do
|
|||
SINCE="$OPTARG days ago"
|
||||
;;
|
||||
w)
|
||||
if [ -n "$SINCE" ]; then
|
||||
if [ -n "$RANGE_SPECIFIED" ]; then
|
||||
warn "-w option is conflict with -d"
|
||||
continue
|
||||
fi
|
||||
RANGE_SPECIFIED=yes
|
||||
|
||||
week_range=${OPTARG}
|
||||
week_start="${week_range%%-*}"
|
||||
|
|
@ -117,7 +127,29 @@ while getopts "hgfd:a:w:m:D:L" opt; do
|
|||
GIT_DATE_FORMAT=${OPTARG}
|
||||
;;
|
||||
g)
|
||||
GIT_PRETTY_FORMAT="%C(yellow)gpg: %G?%Creset"
|
||||
warn "-g option is deprecated, use '-F gpg' instead"
|
||||
USE_GPG_FORMAT=yes
|
||||
;;
|
||||
B)
|
||||
GROUP_BY_BRANCHES=true
|
||||
;;
|
||||
n)
|
||||
MAX_COMMIT_NUM=${OPTARG}
|
||||
;;
|
||||
F)
|
||||
case $OPTARG in
|
||||
gpg)
|
||||
USE_GPG_FORMAT=yes
|
||||
;;
|
||||
authordate)
|
||||
COMMIT_DATE_FORMAT=%ad
|
||||
;;
|
||||
*)
|
||||
warn "Invalid argument for -F: $OPTARG"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
\?)
|
||||
usage
|
||||
|
|
@ -129,7 +161,7 @@ done
|
|||
shift $((OPTIND-1))
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
warn "please upgrate to new-style interface. Run 'git help standup' to get more info."
|
||||
warn "please upgrade to new-style interface. Run 'git help standup' to get more info."
|
||||
if [[ $# -gt 3 ]] ; then
|
||||
usage
|
||||
exit 1
|
||||
|
|
@ -139,16 +171,36 @@ if [[ $# -gt 0 ]]; then
|
|||
UNTIL=$3
|
||||
fi
|
||||
|
||||
AUTHOR=${AUTHOR:="$(git config user.name)"}
|
||||
SINCE=${SINCE:=yesterday}
|
||||
UNTIL=${UNTIL:=today}
|
||||
AUTHOR=${AUTHOR:="$(git config user.name || echo '')"}
|
||||
if [ -z "${AUTHOR}" ]; then
|
||||
warn "please configure an author with 'git config user.name' or specify an author via '-a'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FETCH_LAST_COMMIT=${FETCH_LAST_COMMIT:=false}
|
||||
MAXDEPTH=${MAXDEPTH:=2}
|
||||
GIT_PRETTY_FORMAT="%Cred%h%Creset - %s %Cgreen(%cd) %C(bold blue)<%an>%Creset $GIT_PRETTY_FORMAT"
|
||||
GIT_PRETTY_FORMAT="%Cred%h%Creset - %s %Cgreen(${COMMIT_DATE_FORMAT}) %C(bold blue)<%an>%Creset"
|
||||
GIT_DATE_FORMAT=${GIT_DATE_FORMAT:=relative}
|
||||
if [[ "$USE_GPG_FORMAT" == 'yes' ]]; then
|
||||
GIT_PRETTY_FORMAT="$GIT_PRETTY_FORMAT %C(yellow)gpg: %G?%Creset"
|
||||
fi
|
||||
|
||||
# Handle config of implicit week
|
||||
IMPLICIT_WEEK=$(git config --get git-extras.standup.implicit-week || echo '')
|
||||
if [[ -z "$RANGE_SPECIFIED" ]] && [[ -n "${IMPLICIT_WEEK}" ]]; then
|
||||
week_start=${IMPLICIT_WEEK%%-*}
|
||||
week_end=${IMPLICIT_WEEK##*-}
|
||||
shopt -s nocasematch
|
||||
if [[ "$week_start" == "$(LC_ALL=C date +%a)" ]]; then
|
||||
SINCE="last $week_end"
|
||||
fi
|
||||
UNTIL=today
|
||||
else
|
||||
SINCE=${SINCE:=yesterday}
|
||||
UNTIL=${UNTIL:=today}
|
||||
fi
|
||||
|
||||
GIT_LOG_COMMAND="git --no-pager log \
|
||||
--all
|
||||
--no-merges
|
||||
--since \"$SINCE\"
|
||||
--until \"$UNTIL\"
|
||||
|
|
@ -158,12 +210,37 @@ GIT_LOG_COMMAND="git --no-pager log \
|
|||
--color=$COLOR
|
||||
--pretty=format:'$GIT_PRETTY_FORMAT'
|
||||
--date='$GIT_DATE_FORMAT'"
|
||||
if [[ -n "$MAX_COMMIT_NUM" ]]; then
|
||||
GIT_LOG_COMMAND="$GIT_LOG_COMMAND --max-count=$MAX_COMMIT_NUM"
|
||||
fi
|
||||
|
||||
git_output() {
|
||||
if [ "$GROUP_BY_BRANCHES" = true ]; then
|
||||
local branches
|
||||
branches=$(git branch --sort=-committerdate | awk '{print substr($0, 3)}')
|
||||
for branch in $branches; do
|
||||
# shellcheck disable=SC2086
|
||||
if output=$(eval $GIT_LOG_COMMAND "$branch"); then
|
||||
if [[ -n "$output" ]] ; then
|
||||
echo "${GREEN}${branch}${NORMAL}"
|
||||
echo "$output"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
# TODO optimize:return if the latest commit of a branch is earlier than the 'since' day
|
||||
done
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
eval $GIT_LOG_COMMAND --all
|
||||
fi
|
||||
}
|
||||
|
||||
## For when the command has been run in a non-repo directory
|
||||
if [[ $in_git_repo != 0 ]]; then
|
||||
## Set delimiter to newline for the loop
|
||||
IFS=$'\n'
|
||||
## Recursively search for git repositories
|
||||
# shellcheck disable=SC2086
|
||||
PROJECT_DIRS=$(find $INCLUDE_LINKS . -maxdepth "$MAXDEPTH" -mindepth 0 -name .git)
|
||||
|
||||
# Fetch the latest commits, if required
|
||||
|
|
@ -191,11 +268,12 @@ if [[ $in_git_repo != 0 ]]; then
|
|||
pushd "$DIR" > /dev/null
|
||||
## Show the detail only if it is a git repository
|
||||
if [[ -d ".git" || -f ".git" ]] ; then
|
||||
if GITOUT=$(eval ${GIT_LOG_COMMAND}); then
|
||||
if GITOUT=$(git_output); then
|
||||
## Only output if there is some activities
|
||||
if [[ ! -z "$GITOUT" ]] ; then
|
||||
if [[ -n "$GITOUT" ]] ; then
|
||||
echo "${BOLD}${UNDERLINE}${YELLOW}$(basename "$DIR")${NORMAL}"
|
||||
echo "$GITOUT"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
echo "Repository under $DIR could not be queried." >&2
|
||||
|
|
@ -209,8 +287,8 @@ else
|
|||
git fetch --all > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if GITOUT=$(eval ${GIT_LOG_COMMAND}); then
|
||||
if [[ ! -z "$GITOUT" ]] ; then
|
||||
if GITOUT=$(git_output); then
|
||||
if [[ -n "$GITOUT" ]] ; then
|
||||
echo "$GITOUT"
|
||||
else
|
||||
if [[ $AUTHOR = '.*' ]] ; then
|
||||
|
|
|
|||
216
bin/git-summary
216
bin/git-summary
|
|
@ -3,24 +3,79 @@
|
|||
|
||||
cd "$(git root)" || { echo "Can't cd to top level directory";exit 1; }
|
||||
|
||||
commit=""
|
||||
test $# -ne 0 && commit=$@
|
||||
project=${PWD##*/}
|
||||
PROJECT_FULL_PATH=
|
||||
SUMMARY_BY_LINE=
|
||||
DEDUP_BY_EMAIL=
|
||||
MERGES_ARG=
|
||||
OUTPUT_STYLE=
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--full-path)
|
||||
PROJECT_FULL_PATH=1
|
||||
;;
|
||||
--line)
|
||||
SUMMARY_BY_LINE=1
|
||||
;;
|
||||
--dedup-by-email)
|
||||
DEDUP_BY_EMAIL=1
|
||||
;;
|
||||
--no-merges)
|
||||
MERGES_ARG="--no-merges"
|
||||
;;
|
||||
--output-style)
|
||||
OUTPUT_STYLE="$2"
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
>&2 echo "unknown argument $arg found"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# set the argument back
|
||||
set -- "$@" "$arg"
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -n "$DEDUP_BY_EMAIL" ] && [ -n "$SUMMARY_BY_LINE" ]; then
|
||||
>&2 echo "--dedup-by-email used with --line is not supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$MERGES_ARG" ] && [ -n "$SUMMARY_BY_LINE" ]; then
|
||||
>&2 echo "--no-merges used with --line is not supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
commit="HEAD"
|
||||
if [ -n "$SUMMARY_BY_LINE" ]; then
|
||||
paths=( "$@" )
|
||||
else
|
||||
[ $# -ne 0 ] && commit=$*
|
||||
fi
|
||||
|
||||
if [[ -n "$PROJECT_FULL_PATH" ]]; then
|
||||
project=${PWD/${HOME}/\~}
|
||||
else
|
||||
project=${PWD##*/}
|
||||
fi
|
||||
|
||||
#
|
||||
# get date for the given <commit>
|
||||
#
|
||||
|
||||
date() {
|
||||
git log --pretty='format: %ai' $1 | cut -d ' ' -f 2
|
||||
commit_date() {
|
||||
# the $1 can be empty
|
||||
# shellcheck disable=SC2086
|
||||
git log $MERGES_ARG --pretty='format: %ai' "$1" | cut -d ' ' -f 2
|
||||
}
|
||||
|
||||
#
|
||||
# get active days for the given <commit>
|
||||
#
|
||||
|
||||
active_days() {
|
||||
date $1 | sort -r | uniq | awk '
|
||||
commit_date "$1" | sort -r | uniq | awk '
|
||||
{ sum += 1 }
|
||||
END { print sum }
|
||||
'
|
||||
|
|
@ -29,23 +84,61 @@ active_days() {
|
|||
#
|
||||
# get the commit total
|
||||
#
|
||||
|
||||
commit_count() {
|
||||
git log --oneline $commit | wc -l | tr -d ' '
|
||||
# shellcheck disable=SC2086
|
||||
git rev-list $MERGES_ARG --count "$commit"
|
||||
}
|
||||
|
||||
#
|
||||
# total file count
|
||||
#
|
||||
|
||||
file_count() {
|
||||
git ls-files | wc -l | tr -d ' '
|
||||
}
|
||||
|
||||
#
|
||||
# remove duplicate authors who belong to the same email address
|
||||
#
|
||||
dedup_by_email() {
|
||||
# in:
|
||||
# 27 luo zexuan <LuoZexuan@xxx.com>
|
||||
# 7 罗泽轩 <luozexuan@xxx.com>
|
||||
# out:
|
||||
# 34 luo zexuan
|
||||
LC_ALL=C awk '
|
||||
{
|
||||
sum += $1
|
||||
last_field = tolower($NF)
|
||||
if (last_field in emails) {
|
||||
emails[last_field] += $1
|
||||
} else {
|
||||
email = last_field
|
||||
emails[email] = $1
|
||||
# set commits/email to empty
|
||||
$1=$NF=""
|
||||
sub(/^[[:space:]]+/, "", $0)
|
||||
sub(/[[:space:]]+$/, "", $0)
|
||||
name = $0
|
||||
if (name in names) {
|
||||
# when the same name is associated with existed email,
|
||||
# merge the previous email into the later one.
|
||||
emails[email] += emails[names[name]]
|
||||
emails[names[name]] = 0
|
||||
}
|
||||
names[name] = email
|
||||
}
|
||||
}
|
||||
END {
|
||||
for (name in names) {
|
||||
email = names[name]
|
||||
printf "%6d\t%s\n", emails[email], name
|
||||
}
|
||||
}' | sort -rn -k 1
|
||||
}
|
||||
|
||||
#
|
||||
# list authors
|
||||
#
|
||||
|
||||
format_authors() {
|
||||
# a rare unicode character is used as separator to avoid conflicting with
|
||||
# author name. However, Linux column utility will escape tab if separator
|
||||
|
|
@ -63,65 +156,104 @@ format_authors() {
|
|||
#
|
||||
# fetch repository age from oldest commit
|
||||
#
|
||||
|
||||
repository_age() {
|
||||
git log --reverse --pretty=oneline --format="%ar" | head -n 1 | LC_ALL=C sed 's/ago//'
|
||||
}
|
||||
|
||||
#
|
||||
# fetch repository age of the latest commit
|
||||
#
|
||||
last_active() {
|
||||
git log --pretty=oneline --format="%ar" -n 1
|
||||
}
|
||||
|
||||
#
|
||||
# list the last modified author for each line
|
||||
#
|
||||
single_file() {
|
||||
while read data
|
||||
while read -r data
|
||||
do
|
||||
if [[ $(file "$data") = *text* ]]; then
|
||||
git blame --line-porcelain "$data" 2>/dev/null | grep "^author\ " | LC_ALL=C sed -n 's/^author //p';
|
||||
git blame --line-porcelain "$data" 2>/dev/null | grep "^author " | LC_ALL=C sed -n 's/^author //p';
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
current_branch_name() {
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
}
|
||||
|
||||
#
|
||||
# list the author for all file
|
||||
#
|
||||
lines() {
|
||||
git ls-files | single_file
|
||||
git ls-files -- "$@" | single_file
|
||||
}
|
||||
|
||||
#
|
||||
# get the number of the lines
|
||||
#
|
||||
line_count() {
|
||||
lines | wc -l
|
||||
lines "$@" | wc -l
|
||||
}
|
||||
|
||||
result() {
|
||||
lines | sort | uniq -c | sort -rn | awk '
|
||||
{ args[NR] = $0; sum += $0 }
|
||||
END {
|
||||
for (i = 1; i <= NR; ++i) {
|
||||
printf " %s, %2.1f%%\n", args[i], 100 * args[i] / sum
|
||||
}
|
||||
}
|
||||
' | column -t -s,
|
||||
uncommitted_changes_count() {
|
||||
git status --porcelain | wc -l
|
||||
}
|
||||
|
||||
# summary
|
||||
|
||||
echo
|
||||
echo " project : $project"
|
||||
COLUMN_CMD_DELIMTER="¬" # Hopefully, this symbol is not used in branch names... I use it as a separator for columns
|
||||
SP="$COLUMN_CMD_DELIMTER|"
|
||||
|
||||
if test "$1" = "--line"; then
|
||||
echo " lines : $(line_count)"
|
||||
echo " authors :"
|
||||
lines | sort | uniq -c | sort -rn | format_authors
|
||||
else
|
||||
|
||||
echo " repo age :" $(repository_age)
|
||||
echo " active :" $(active_days) days
|
||||
echo " commits :" $(commit_count)
|
||||
if test "$commit" = ""; then
|
||||
echo " files :" $(file_count)
|
||||
print_summary_by_line() {
|
||||
if [ "$OUTPUT_STYLE" = "tabular" ]; then
|
||||
tabular_headers="# Repo $SP Lines"
|
||||
echo -e "$tabular_headers\n$project $SP $(line_count "${paths[@]}")" | column -t -s "$COLUMN_CMD_DELIMTER"
|
||||
elif [ "$OUTPUT_STYLE" = "oneline" ]; then
|
||||
echo "$project / lines: $(line_count "${paths[@]}")"
|
||||
elif [ -n "$SUMMARY_BY_LINE" ]; then
|
||||
echo
|
||||
echo " project : $project"
|
||||
echo " lines : $(line_count "${paths[@]}")"
|
||||
echo " authors :"
|
||||
lines "${paths[@]}" | sort | uniq -c | sort -rn | format_authors
|
||||
fi
|
||||
echo " authors : "
|
||||
git shortlog -n -s $commit | format_authors
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
if [ "$OUTPUT_STYLE" = "tabular" ]; then
|
||||
tabular_headers="# Repo $SP Age $SP Last active $SP Active on $SP Commits $SP Uncommitted $SP Branch"
|
||||
echo -e "$tabular_headers\n$project $SP $(repository_age) $SP $(last_active) $SP $(active_days "$commit") days $SP $(commit_count "$commit") $SP $(uncommitted_changes_count) $SP $(current_branch_name)" | column -t -s "$COLUMN_CMD_DELIMTER"
|
||||
elif [ "$OUTPUT_STYLE" = "oneline" ]; then
|
||||
echo "$project / age: $(repository_age) / last active: $(last_active) / active on $(active_days "$commit") days / commits: $(commit_count "$commit") / uncommitted: $(uncommitted_changes_count) / branch: $(current_branch_name)"
|
||||
else
|
||||
echo
|
||||
echo " project : $project"
|
||||
echo " repo age : $(repository_age)"
|
||||
echo " branch: : $(current_branch_name)"
|
||||
echo " last active : $(last_active)"
|
||||
echo " active on : $(active_days "$commit") days"
|
||||
echo " commits : $(commit_count "$commit")"
|
||||
|
||||
# The file count doesn't support passing a git ref so ignore it if a ref is given
|
||||
if [ "$commit" = "HEAD" ]; then
|
||||
echo " files : $(file_count)"
|
||||
fi
|
||||
echo " uncommitted : $(uncommitted_changes_count)"
|
||||
echo " authors : "
|
||||
if [ -n "$DEDUP_BY_EMAIL" ]; then
|
||||
# the $commit can be empty
|
||||
# shellcheck disable=SC2086
|
||||
git shortlog $MERGES_ARG -n -s -e "$commit" | dedup_by_email | format_authors
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
git shortlog $MERGES_ARG -n -s "$commit" | format_authors
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$SUMMARY_BY_LINE" ]; then
|
||||
print_summary_by_line
|
||||
else
|
||||
print_summary
|
||||
fi
|
||||
|
|
|
|||
27
bin/git-sync
27
bin/git-sync
|
|
@ -8,6 +8,7 @@ Usage:
|
|||
${command} [<remote> <branch>]
|
||||
${command} -h | --help
|
||||
${command} -s | --soft
|
||||
${command} -f | --force
|
||||
|
||||
Sync local branch with <remote>/<branch>.
|
||||
When <remote> and <branch> are not specified on the command line, upstream of local branch will be used by default.
|
||||
|
|
@ -22,6 +23,9 @@ Examples:
|
|||
|
||||
Sync without cleaning untracked files:
|
||||
${command} -s
|
||||
|
||||
Sync without interaction:
|
||||
${command} -f
|
||||
EOS
|
||||
}
|
||||
|
||||
|
|
@ -36,6 +40,9 @@ function main()
|
|||
-s | --soft)
|
||||
local soft="true"
|
||||
;;
|
||||
-f | --force)
|
||||
local force="YES"
|
||||
;;
|
||||
* )
|
||||
if [ "${remote}" = "" ]; then
|
||||
local remote="$1"
|
||||
|
|
@ -52,14 +59,14 @@ function main()
|
|||
done
|
||||
|
||||
local remote_branch
|
||||
if [ "${remote}" = "" ]; then
|
||||
if ! remote_branch="$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null)"; then
|
||||
if [ -z "${remote}" ]; then
|
||||
if ! remote_branch="$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null)"; then
|
||||
echo "There is no upstream information of local branch."
|
||||
exit 1
|
||||
fi
|
||||
local branch="$(git rev-parse --abbrev-ref --symbolic-full-name @)"
|
||||
local remote=$(git config "branch.${branch}.remote")
|
||||
elif [ "${branch}" = "" ]; then
|
||||
elif [ -z "${branch}" ]; then
|
||||
echo -e "Error: too few arguments.\n"
|
||||
_usage
|
||||
exit 1
|
||||
|
|
@ -67,10 +74,16 @@ function main()
|
|||
remote_branch="${remote}/${branch}"
|
||||
fi
|
||||
|
||||
echo -n "Are you sure you want to clean all changes & sync with '${remote_branch}'? [y/N]: "
|
||||
local res
|
||||
read res
|
||||
case "${res}" in
|
||||
if [ "${force}" != "YES" ]; then
|
||||
if [ "${soft}" = "true" ]; then
|
||||
echo -n "Are you sure you want to sync with '${remote_branch}'? [y/N]: "
|
||||
else
|
||||
echo -n "Are you sure you want to clean all changes & sync with '${remote_branch}'? [y/N]: "
|
||||
fi
|
||||
local force
|
||||
read -r force
|
||||
fi
|
||||
case "${force}" in
|
||||
"Y" | "y" | "yes" | "Yes" | "YES" )
|
||||
if [ "${soft}" = "true" ]; then
|
||||
git fetch "${remote}" "${branch}" && git reset --hard "${remote_branch}"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ USAGE(){
|
|||
|
||||
test $# -lt 1 && USAGE
|
||||
|
||||
for filename in $@; do
|
||||
for filename in "$@"; do
|
||||
touch "$filename" \
|
||||
&& git add "$filename"
|
||||
done
|
||||
|
|
|
|||
57
bin/git-undo
57
bin/git-undo
|
|
@ -1,6 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
back="^"
|
||||
cstr="commits"
|
||||
ccnt=$(git rev-list --count HEAD)
|
||||
if [ "$ccnt" -eq 1 ]; then cstr="commit"; fi
|
||||
parm3=""
|
||||
|
||||
function _undo()
|
||||
{
|
||||
type=${1:-soft}
|
||||
undo_cnt=${2:-1}
|
||||
reset=${3:-""}
|
||||
|
||||
if [ "$undo_cnt" -gt "$ccnt" ]; then
|
||||
echo "Only $ccnt $cstr, cannot undo $undo_cnt"
|
||||
elif [ "$type" = "hard" ] && [ "$ccnt" -eq "$undo_cnt" ]; then
|
||||
echo "Cannot hard undo all commits"
|
||||
elif [ "$type" = "soft" ] && [ "$ccnt" -eq 1 ]; then
|
||||
git update-ref -d HEAD
|
||||
else
|
||||
git reset "--$type" "HEAD~$undo_cnt"
|
||||
fi
|
||||
if [ "$reset" != "" ]; then git reset; fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
-h)
|
||||
|
|
@ -12,9 +33,8 @@ EOL
|
|||
read -r res
|
||||
case "${res}" in
|
||||
"Y" | "y")
|
||||
test $2 -gt 1 > /dev/null 2>&1 && back="~$2"
|
||||
git reset --hard HEAD$back
|
||||
exit $?
|
||||
parm1=hard
|
||||
parm2=${2:-1}
|
||||
;;
|
||||
* )
|
||||
exit 0
|
||||
|
|
@ -22,16 +42,31 @@ EOL
|
|||
esac
|
||||
;;
|
||||
--hard)
|
||||
test $2 -gt 1 > /dev/null 2>&1 && back="~$2"
|
||||
git reset --hard HEAD$back
|
||||
parm1=hard
|
||||
parm2=${2:-1}
|
||||
;;
|
||||
-s|--soft)
|
||||
test $2 -gt 1 > /dev/null 2>&1 && back="~$2"
|
||||
git reset --soft HEAD$back
|
||||
parm1=soft
|
||||
parm2=${2:-1}
|
||||
parm3=reset
|
||||
;;
|
||||
"")
|
||||
parm1=soft
|
||||
parm2=1
|
||||
;;
|
||||
*[!0-9]*)
|
||||
echo "Invalid parameter: $1"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
test $1 -gt 1 > /dev/null 2>&1 && back="~$1"
|
||||
git reset --soft HEAD$back
|
||||
git reset
|
||||
parm1=soft
|
||||
parm2="$1"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ ! $parm2 =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "Invalid undo count: $parm2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_undo "$parm1" "$parm2" "$parm3"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
filename=$1
|
||||
test -z $filename && echo "filename required." 1>&2 && exit 1
|
||||
git update-index --no-skip-worktree $filename
|
||||
filename="$1"
|
||||
test -z "$filename" && echo "filename required." 1>&2 && exit 1
|
||||
git update-index --no-skip-worktree "$filename"
|
||||
|
|
|
|||
14
bin/git-unwip
Executable file
14
bin/git-unwip
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Based on scripts from git-utils:
|
||||
# * https://github.com/ddollar/git-utils/blob/master/git-unwip
|
||||
|
||||
# Check if the last commit is a 'WIP' commit
|
||||
LAST_COMMIT=`git log -1 --pretty=%B | tr -d '[:space:]'`
|
||||
|
||||
if [ 'WIP' != $LAST_COMMIT ]; then
|
||||
echo 'Last commit is not a WIP commit, so it will not be unWIP-ed.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git undo --soft
|
||||
131
bin/git-utimes
Executable file
131
bin/git-utimes
Executable file
|
|
@ -0,0 +1,131 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Change files modification time to their last commit date
|
||||
#
|
||||
|
||||
# Bash unofficial strict mode
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
if [[ "${1:-}" == "--newer" ]]; then
|
||||
op=le
|
||||
shift
|
||||
else
|
||||
op=eq
|
||||
fi
|
||||
|
||||
# BSD systems
|
||||
if date -j &>/dev/null; then
|
||||
stat_flags="-f %m"
|
||||
date_flags="-r"
|
||||
else
|
||||
# Non-BSD systems
|
||||
stat_flags="-c %Y"
|
||||
date_flags="-d@"
|
||||
fi
|
||||
|
||||
bash_opts=()
|
||||
if bash --help 2>&1 | grep -q -- '--noprofile'; then
|
||||
bash_opts+=(--noprofile)
|
||||
fi
|
||||
if bash --help 2>&1 | grep -q -- '--norc'; then
|
||||
bash_opts+=(--norc)
|
||||
fi
|
||||
|
||||
status_opts=(--porcelain --short)
|
||||
# %ct: committer date, UNIX timestamp / %at: author date, UNIX timestamp
|
||||
log_opts=(--format='%ct')
|
||||
if git status --help 2>&1 | grep -q -- "--no-renames"; then
|
||||
status_opts+=(--no-renames)
|
||||
log_opts+=(--no-renames)
|
||||
fi
|
||||
if git status --help 2>&1 | grep -q -- "--untracked-files"; then
|
||||
status_opts+=(--untracked-files=no)
|
||||
fi
|
||||
if git status --help 2>&1 | grep -q -- "--ignored"; then
|
||||
status_opts+=(--ignored=no)
|
||||
fi
|
||||
|
||||
prefix="$(git rev-parse --show-prefix) "
|
||||
strip="${#prefix}"
|
||||
|
||||
tmpfile=$(mktemp)
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -f '${tmpfile}'" 0
|
||||
|
||||
awk_flags=(
|
||||
-F'\t'
|
||||
-v date_flags="${date_flags}"
|
||||
-v op="${op}"
|
||||
-v stat_flags="${stat_flags}"
|
||||
-v strip="${strip}"
|
||||
-v tmpfile="${tmpfile}"
|
||||
)
|
||||
|
||||
# sanity check, not required:
|
||||
if awk --help 2>&1 | grep -q -- '--posix'; then
|
||||
awk_flags+=(--posix)
|
||||
fi
|
||||
|
||||
read -r -d '' awk_script <<"EOF" || true
|
||||
BEGIN {
|
||||
seen[""]=1
|
||||
print "#!/usr/bin/env bash"
|
||||
print "set +e"
|
||||
print "t() {"
|
||||
print " test -e \"$2\" || return 0"
|
||||
printf(" test \"$(stat %s \"$2\" 2>/dev/null)\" -%s \"$1\" && return 0\n", stat_flags, op)
|
||||
if (date_flags == "-d@") {
|
||||
print " echo \"+ touch -h -d@$1 $2\""
|
||||
print " touch -h -d@$1 \"$2\""
|
||||
} else {
|
||||
print " t=$(date -r$1 \"+%Y%m%d%H%M.%S\")"
|
||||
print " echo \"+ touch -h -t $t $2\""
|
||||
print " touch -h -t $t \"$2\""
|
||||
}
|
||||
print "}"
|
||||
}
|
||||
FILENAME==tmpfile {
|
||||
skip[$1]=1
|
||||
next
|
||||
}
|
||||
# skip blank lines
|
||||
!/^$/ {
|
||||
# skip deletes
|
||||
if (substr($1, length($1), 1) ~ /D/) {
|
||||
next
|
||||
}
|
||||
if (NF == 1) {
|
||||
ct=$1
|
||||
next
|
||||
}
|
||||
$2 = substr($2, strip, length($2)- strip + 1)
|
||||
if ($2 in seen) {
|
||||
next
|
||||
}
|
||||
if ($2 in skip) {
|
||||
next
|
||||
}
|
||||
seen[$2]=1
|
||||
# remove enclosing double quotes that git adds:
|
||||
if (substr($2, 1, 1) == "\"" && substr($2, length($2), 1) == "\"") {
|
||||
$2 = substr($2, 2, length($2) - 2)
|
||||
# unescape remaining double quotes
|
||||
gsub(/\\"/, "\"", $2)
|
||||
# unescape escaped backslashes
|
||||
gsub(/\\\\/, "\\", $2)
|
||||
}
|
||||
# escape apostrophes: ' => '\''
|
||||
gsub(/'/, "'\\''", $2)
|
||||
printf("t %s '%s'\n", ct, $2)
|
||||
}
|
||||
EOF
|
||||
|
||||
# prefix is stripped:
|
||||
git --no-pager status "${status_opts[@]}" . \
|
||||
| cut -c 4- >"${tmpfile}"
|
||||
|
||||
# prefix is not stripped:
|
||||
git --no-pager log --raw --no-merges "${log_opts[@]}" . \
|
||||
| awk "${awk_flags[@]}" "${awk_script}" "${tmpfile}" - \
|
||||
| BASH_ENV='' bash "${bash_opts[@]}" -
|
||||
8
bin/git-wip
Executable file
8
bin/git-wip
Executable file
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Based on scripts from git-utils:
|
||||
# * https://github.com/ddollar/git-utils/blob/master/git-wip
|
||||
# * https://github.com/ddollar/git-utils/blob/master/git-addremove
|
||||
|
||||
git add --all
|
||||
git commit --all --message="WIP"
|
||||
|
|
@ -3,10 +3,10 @@ index e49cd24..4ae28b5 100755
|
|||
--- a/bin/git-extras
|
||||
+++ b/bin/git-extras
|
||||
@@ -4,13 +4,12 @@ VERSION="4.3.0"
|
||||
INSTALL_SCRIPT="https://raw.githubusercontent.com/tj/git-extras/master/install.sh"
|
||||
INSTALL_SCRIPT="https://raw.githubusercontent.com/tj/git-extras/main/install.sh"
|
||||
|
||||
update() {
|
||||
- local bin="$(which git-extras)"
|
||||
- local bin="$(command -v git-extras)"
|
||||
- local prefix=${bin%/*/*}
|
||||
- local orig=$PWD
|
||||
-
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ err() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
if ! test "$(which column)"; then
|
||||
err "Need to install dependency 'column' before installation"
|
||||
if ! command -v column >/dev/null 2>&1; then
|
||||
err "Need to install dependency 'column' before installation (can be found in bsdmainutils)"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ err() {
|
|||
exit 1
|
||||
}
|
||||
|
||||
make_doc() {
|
||||
echo "touch man/git-$1.md && make man/git-$1.{1,html}"
|
||||
}
|
||||
|
||||
check_bash_script() {
|
||||
local cmd="git-$1"
|
||||
|
||||
|
|
@ -21,17 +25,17 @@ check_bash_script() {
|
|||
|
||||
check_git_extras_cmd_list() {
|
||||
local whitelist=('extras')
|
||||
for cmd in ${whitelist[*]}; do
|
||||
for cmd in "${whitelist[@]}"; do
|
||||
test "$1" == "$cmd" && return
|
||||
done
|
||||
|
||||
grep "\- \*\*git\-$1(1)\*\*" man/git-extras.md >/dev/null \
|
||||
|| err "Add git-$1 in the list of commands in man/git-extras.md"
|
||||
|| err "Add git-$1 in the list of commands in man/git-extras.md via $(make_doc "$1")"
|
||||
}
|
||||
|
||||
check_man_page_index() {
|
||||
grep "git\-$1(1) git\-$1" man/index.txt >/dev/null \
|
||||
|| err "Add git-$1 to index.txt"
|
||||
|| err "Add git-$1 to index.txt via $(make_doc "$1")"
|
||||
}
|
||||
|
||||
check_documentation() {
|
||||
|
|
@ -40,7 +44,12 @@ check_documentation() {
|
|||
|
||||
if [ ! -f "man/$cmd.1" ] || [ ! -f "man/$cmd.html" ]
|
||||
then
|
||||
err "Run 'make docs' to create man/$cmd.1 and man/$cmd.html"
|
||||
err "Create man/$cmd.1 and man/$cmd.html via $(make_doc "$1")"
|
||||
fi
|
||||
|
||||
if [ "man/$cmd.md" -nt "man/$cmd.1" ] || [ "man/$cmd.md" -nt "man/$cmd.html" ]
|
||||
then
|
||||
err "man/$cmd.md, man/$cmd.1, and man/$cmd.html all exist, but man/$cmd.md is newer. You should rm man/$cmd.{1,html} && $(make_doc "$1")"
|
||||
fi
|
||||
|
||||
check_git_extras_cmd_list "$@"
|
||||
|
|
@ -50,7 +59,7 @@ check_documentation() {
|
|||
check_Commands_page() {
|
||||
# These are special cases. All listed together, so we ignore them
|
||||
local whitelist=('bug' 'chore' 'feature' 'refactor')
|
||||
for cmd in ${whitelist[*]}; do
|
||||
for cmd in "${whitelist[@]}"; do
|
||||
test "$1" == "$cmd" && return
|
||||
done
|
||||
|
||||
|
|
@ -73,12 +82,9 @@ check() {
|
|||
check_completion "$1"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo >&2 "Usage: ./check_integrity.sh <command-name> [<command-name2> ...]"
|
||||
exit 0
|
||||
}
|
||||
test $# == 0 && set -- $(find bin | cut -b 5- | xargs)
|
||||
|
||||
test $# == 0 && usage
|
||||
./bin/git-utimes --newer
|
||||
|
||||
for name in "$@"; do
|
||||
name=${name#git-}
|
||||
|
|
@ -87,4 +93,3 @@ for name in "$@"; do
|
|||
done
|
||||
|
||||
echo 'All done'
|
||||
exit 0
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue