mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-05 21:46:49 -04:00
Compare commits
1242
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ad3fac63 | ||
|
|
ae4a579153 | ||
|
|
da86096e19 | ||
|
|
e1d973d62a | ||
|
|
0489b11c0c | ||
|
|
c7a9b9ca07 | ||
|
|
f2db9fa3f9 | ||
|
|
b9107d5fc8 | ||
|
|
bfe2dd4ed8 | ||
|
|
7652d579f5 | ||
|
|
73bcbe4ee2 | ||
|
|
cd01e4e7c2 | ||
|
|
c5de9cfd8e | ||
|
|
1129e0e4a0 | ||
|
|
981f1fa7aa | ||
|
|
cad4581d05 | ||
|
|
f0af42270e | ||
|
|
e0377f2bce | ||
|
|
968060a5ec | ||
|
|
07fe828f60 | ||
|
|
b004b2e275 | ||
|
|
7a670964cd | ||
|
|
a138a31c72 | ||
|
|
31456a8caa | ||
|
|
22764cd207 | ||
|
|
be21328c69 | ||
|
|
3d14893c65 | ||
|
|
8813587961 | ||
|
|
13bd4b964f | ||
|
|
eae76a97e9 | ||
|
|
34214af41f | ||
|
|
38aa5b89ab | ||
|
|
2e5b570bb6 | ||
|
|
a5eec48b4b | ||
|
|
94cf2cc7df | ||
|
|
ac30aee1b8 | ||
|
|
d3780fd57d | ||
|
|
5959f7bc8e | ||
|
|
436240bbeb | ||
|
|
2317dac730 | ||
|
|
08bd36ea78 | ||
|
|
ab31991e13 | ||
|
|
4df8f87715 | ||
|
|
62a018c1d4 | ||
|
|
b26ff43d9e | ||
|
|
a047fba9f7 | ||
|
|
974016cfba | ||
|
|
5b6dbe57b1 | ||
|
|
92d4073b2a | ||
|
|
c27a7e0816 | ||
|
|
f3c9443ec8 | ||
|
|
71a62b7573 | ||
|
|
61313e5dfa | ||
|
|
94a1c27916 | ||
|
|
6da4f9a787 | ||
|
|
398ceb1dd9 | ||
|
|
6788825ed3 | ||
|
|
2335772db6 | ||
|
|
1285554cb2 | ||
|
|
232be05785 | ||
|
|
8990026358 | ||
|
|
bd782f16dd | ||
|
|
7be82d4713 | ||
|
|
5dbdbd8425 | ||
|
|
9b73b68f95 | ||
|
|
c3715d0f86 | ||
|
|
696b8ba457 | ||
|
|
e205c6ba7f | ||
|
|
c6df856079 | ||
|
|
26c3e0d333 | ||
|
|
4b6479b25f | ||
|
|
1ab1fb3599 | ||
|
|
1d502d3245 | ||
|
|
bb01648521 | ||
|
|
32cfe7a5c3 | ||
|
|
b795d91fa8 | ||
|
|
ccc620e5fc | ||
|
|
34d7afc0e9 | ||
|
|
22dc7fece9 | ||
|
|
c3d1a79a89 | ||
|
|
63a523c2fc | ||
|
|
d146d834c2 | ||
|
|
68edfa20b4 | ||
|
|
bfe9f233ac | ||
|
|
741d9a26b6 | ||
|
|
98e5fd70fb | ||
|
|
b34de70c99 | ||
|
|
1e123e2124 | ||
|
|
02aeb6101c | ||
|
|
2ccd9980e3 | ||
|
|
db0a1586d9 | ||
|
|
4e441127f3 | ||
|
|
cf40a5b077 | ||
|
|
26132cf5bd | ||
|
|
a67eda39a5 | ||
|
|
8e1464f720 | ||
|
|
a62a5089d6 | ||
|
|
4967e5136e | ||
|
|
68c966567c | ||
|
|
20a4aeab6e | ||
|
|
a5620ebe3a | ||
|
|
1b245ef5f6 | ||
|
|
a08c86c182 | ||
|
|
4cd15a36e3 | ||
|
|
13a35408e6 | ||
|
|
1a76a7da09 | ||
|
|
8a16f24ecb | ||
|
|
e2b4d9cff3 | ||
|
|
b2c457366a | ||
|
|
8b8343b8a9 | ||
|
|
f98da780de | ||
|
|
c401f34530 | ||
|
|
ddd6323aa5 | ||
|
|
7e92dbfd3d | ||
|
|
dbc21af3b1 | ||
|
|
6f8244e3fe | ||
|
|
cf27fd827b | ||
|
|
a7c97400c6 | ||
|
|
5e9fe2be80 | ||
|
|
d406ec06af | ||
|
|
7ec784e2a0 | ||
|
|
93af0016f7 | ||
|
|
a171ec4294 | ||
|
|
deee5fa957 | ||
|
|
44160ef844 | ||
|
|
dd2bffc278 | ||
|
|
9eb9b369ff | ||
|
|
fafa4280f5 | ||
|
|
5a5cd849d1 | ||
|
|
6a6316cfb6 | ||
|
|
779e6f95a3 | ||
|
|
44ad36bb39 | ||
|
|
08a8b067a5 | ||
|
|
15b25b5afb | ||
|
|
27ad75de16 | ||
|
|
3af545daf7 | ||
|
|
57f9493770 | ||
|
|
629b7ba1b8 | ||
|
|
43e04febee | ||
|
|
c08a5fe4e7 | ||
|
|
92dd80c3e3 | ||
|
|
899e25b208 | ||
|
|
906d21f3ce | ||
|
|
7780f1264a | ||
|
|
f3718ddfb0 | ||
|
|
f9ba2dac9d | ||
|
|
6cb2ac6fcc | ||
|
|
6b9cf72e79 | ||
|
|
92f13fc56e | ||
|
|
06496ccd17 | ||
|
|
03a075c223 | ||
|
|
eef70dbdf6 | ||
|
|
f5329440fc | ||
|
|
4f6d3fb592 | ||
|
|
187a2f0cc2 | ||
|
|
f6457c4def | ||
|
|
66a04e4273 | ||
|
|
ffedd84e92 | ||
|
|
ab0b0da850 | ||
|
|
b85687797d | ||
|
|
a8921a13cb | ||
|
|
837f7456ab | ||
|
|
ddf5e24499 | ||
|
|
ca6d88080c | ||
|
|
1b7ded6df3 | ||
|
|
36a4696573 | ||
|
|
343db7b3f1 | ||
|
|
4ac77f4575 | ||
|
|
373b1970ca | ||
|
|
5b613f5bc7 | ||
|
|
8c385731f7 | ||
|
|
e79b4259e4 | ||
|
|
f4d922bc80 | ||
|
|
b2011dca35 | ||
|
|
19d0048cc4 | ||
|
|
7c51ec21bf | ||
|
|
39ea5d9ab1 | ||
|
|
205357a44f | ||
|
|
c9c556beba | ||
|
|
b82c72b63d | ||
|
|
dbdabb34f3 | ||
|
|
c1a65546ad | ||
|
|
2c9bca8b57 | ||
|
|
880528b2e4 | ||
|
|
e1b4d625c7 | ||
|
|
a957c5542f | ||
|
|
f085d10c46 | ||
|
|
1269938ee6 | ||
|
|
557dfc5a6d | ||
|
|
c5baa5da3a | ||
|
|
3284d69886 | ||
|
|
116c18e957 | ||
|
|
e93617b1de | ||
|
|
aac2535104 | ||
|
|
993d66a8ff | ||
|
|
ab797fe986 | ||
|
|
4bfda1a78c | ||
|
|
91cb33db85 | ||
|
|
7492521829 | ||
|
|
35af886f55 | ||
|
|
f45ecbc19a | ||
|
|
51eb6d7c7d | ||
|
|
38ec4e646f | ||
|
|
ef1daf314a | ||
|
|
ab643749e8 | ||
|
|
2d0c96466a | ||
|
|
f6ace8380f | ||
|
|
b4aa68d0b3 | ||
|
|
4a97fb80f3 | ||
|
|
8f1a04d095 | ||
|
|
e5f4de8d34 | ||
|
|
ce3fe37787 | ||
|
|
6cf6941a77 | ||
|
|
0fbed71f15 | ||
|
|
22a38c9f50 | ||
|
|
6343fb57d6 | ||
|
|
5af0ea85fc | ||
|
|
a4e9181a6b | ||
|
|
f5d57f7cc7 | ||
|
|
fc7b10f557 | ||
|
|
b75c177c31 | ||
|
|
9b152d7619 | ||
|
|
b98ae1c773 | ||
|
|
7d787afb2c | ||
|
|
af842e40d4 | ||
|
|
6fcb7eb8bb | ||
|
|
c5cf1b2428 | ||
|
|
d890c68cd0 | ||
|
|
0aba686f97 | ||
|
|
b91b40ba4d | ||
|
|
c4927e21c5 | ||
|
|
6afcc5bda8 | ||
|
|
9fc7a5177b | ||
|
|
fdff2dec79 | ||
|
|
9124d8dbaa | ||
|
|
4404aacdee | ||
|
|
8f5ce14dc0 | ||
|
|
866e80529b | ||
|
|
010b0ae923 | ||
|
|
a7041cf492 | ||
|
|
da3e0f7147 | ||
|
|
269d01233f | ||
|
|
615ff09afa | ||
|
|
772388294a | ||
|
|
e09b38153c | ||
|
|
cd62c719f1 | ||
|
|
36e7524146 | ||
|
|
189f39de2b | ||
|
|
5b80c0c792 | ||
|
|
d8b3c0e568 | ||
|
|
f69eb6dc48 | ||
|
|
e0a2d97f0f | ||
|
|
66d0ce841c | ||
|
|
6bb8c180b2 | ||
|
|
5558d873af | ||
|
|
380855d4e8 | ||
|
|
88e7c44552 | ||
|
|
ac0524f7cb | ||
|
|
10e29ce7dd | ||
|
|
618fe533f8 | ||
|
|
01ff18dd92 | ||
|
|
af0897f18f | ||
|
|
b7673577a2 | ||
|
|
00c55d5711 | ||
|
|
0677a58e9f | ||
|
|
b3a60ce407 | ||
|
|
b63321a302 | ||
|
|
a4354ccdfb | ||
|
|
aa81e191e2 | ||
|
|
496308e023 | ||
|
|
98c569749f | ||
|
|
047380f311 | ||
|
|
b2ff09ec0c | ||
|
|
dd6bfa1680 | ||
|
|
0a5e9b2d60 | ||
|
|
8b99a3c949 | ||
|
|
af6d072cc6 | ||
|
|
7270dea48d | ||
|
|
69153acfdb | ||
|
|
b4fbfd20cb | ||
|
|
ef99e47d09 | ||
|
|
580818e935 | ||
|
|
1c098ff82a | ||
|
|
34f8f7293c | ||
|
|
caad553502 | ||
|
|
723b92916d | ||
|
|
653994845e | ||
|
|
bbad3a70ce | ||
|
|
1869fda800 | ||
|
|
5396a70661 | ||
|
|
82a3d33ce3 | ||
|
|
325800a72e | ||
|
|
9f8ae76189 | ||
|
|
8a77e51576 | ||
|
|
145795c0b0 | ||
|
|
cbe6dd7b2f | ||
|
|
b6ca9090f4 | ||
|
|
5d13e3cf76 | ||
|
|
9e5ceaa1ec | ||
|
|
ba0c00b5d1 | ||
|
|
145fb6191c | ||
|
|
7e14d88dc9 | ||
|
|
e6a07b3f03 | ||
|
|
28923fc9d0 | ||
|
|
19bef17042 | ||
|
|
170c4ecb8c | ||
|
|
de1c495704 | ||
|
|
fccfbf1f63 | ||
|
|
05fb12b1d5 | ||
|
|
9cf1ca10a2 | ||
|
|
dc6863b83d | ||
|
|
13af335b37 | ||
|
|
92aab21d3a | ||
|
|
e6ef1642fa | ||
|
|
84333eebc3 | ||
|
|
7f6eea2a55 | ||
|
|
06624e85d6 | ||
|
|
5616d6a9bc | ||
|
|
5c3aacb4cb | ||
|
|
2b5c814080 | ||
|
|
4ba85608c8 | ||
|
|
a63c660f28 | ||
|
|
fab7ca2b58 | ||
|
|
7b0e06d885 | ||
|
|
426375b7cd | ||
|
|
f933a2f7ec | ||
|
|
ed61b9a7f2 | ||
|
|
d8c1eb879b | ||
|
|
c02408bba0 | ||
|
|
f3dba743f0 | ||
|
|
53f0c4aeff | ||
|
|
84e82ea8b6 | ||
|
|
8487bc397d | ||
|
|
93aee0dca0 | ||
|
|
4d8b8b647a | ||
|
|
2385c1d111 | ||
|
|
5d509efe19 | ||
|
|
b9a75ee0ed | ||
|
|
d102f12304 | ||
|
|
6396d1ce03 | ||
|
|
c59e6b6451 | ||
|
|
1cedfa463b | ||
|
|
9b035aed67 | ||
|
|
ce9cdd8d78 | ||
|
|
f774b7eb5c | ||
|
|
e4b4b6d5f4 | ||
|
|
93251db67e | ||
|
|
de52a68b53 | ||
|
|
42ebf1947a | ||
|
|
c995e7ef2e | ||
|
|
04fcb78c0c | ||
|
|
bd8518355e | ||
|
|
f93cb54b5d | ||
|
|
0b70dfbf46 | ||
|
|
38876ba141 | ||
|
|
57786fbb1f | ||
|
|
e295ccefab | ||
|
|
1fdcc29277 | ||
|
|
6da9d55e47 | ||
|
|
ba85f93fb3 | ||
|
|
cdbec3997d | ||
|
|
fb675b79f8 | ||
|
|
f30be824b3 | ||
|
|
e1c3ef6629 | ||
|
|
a70bb0a7aa | ||
|
|
7718cb009b | ||
|
|
1337a943fe | ||
|
|
471ea39758 | ||
|
|
c3f0b5cb4a | ||
|
|
3675570a39 | ||
|
|
68495ea0ee | ||
|
|
53363b761c | ||
|
|
96c5cbe34e | ||
|
|
b8a0473c68 | ||
|
|
571141ea7c | ||
|
|
3b29705a78 | ||
|
|
28dd7f9467 | ||
|
|
150cc70698 | ||
|
|
c92e9d9bdc | ||
|
|
e23337f8f5 | ||
|
|
73019574a8 | ||
|
|
9b5269b490 | ||
|
|
e8db27b0b3 | ||
|
|
337a0dbc9b | ||
|
|
5870133924 | ||
|
|
fa79c92748 | ||
|
|
251bfb6a24 | ||
|
|
377eced31a | ||
|
|
fadc2893d2 | ||
|
|
1e59de2768 | ||
|
|
1d4448d691 | ||
|
|
2c33f0ce1f | ||
|
|
14b3e0574c | ||
|
|
318a399bfb | ||
|
|
7764e6d1cb | ||
|
|
1a9ce9db94 | ||
|
|
9a3db0dfbd | ||
|
|
d65b21d6b8 | ||
|
|
435a835c51 | ||
|
|
4f2bebe453 | ||
|
|
7d2163d632 | ||
|
|
561afa9901 | ||
|
|
a8797c7261 | ||
|
|
a82e26d11e | ||
|
|
2cf8e7bc5c | ||
|
|
6932e04708 | ||
|
|
30db7234d9 | ||
|
|
0d5c748fe8 | ||
|
|
e42cbf95ae | ||
|
|
0360b82aab | ||
|
|
81b497d186 | ||
|
|
e9d050c5d5 | ||
|
|
5c56bc7015 | ||
|
|
0608fc6471 | ||
|
|
64a1a455d6 | ||
|
|
bd975a8dcb | ||
|
|
e5fa9e1c4a | ||
|
|
e8d84a1f2c | ||
|
|
fd18db6ba2 | ||
|
|
36fa25fa6d | ||
|
|
2f4437591e | ||
|
|
d12ceeb1ec | ||
|
|
1ec87364fe | ||
|
|
7c687938a5 | ||
|
|
744519de60 | ||
|
|
b8f4cd0ef6 | ||
|
|
287195b5b2 | ||
|
|
e1b341e174 | ||
|
|
b1523c3f07 | ||
|
|
c3c5753a35 | ||
|
|
272e41929c | ||
|
|
ac4767bb2a | ||
|
|
d1f8c45099 | ||
|
|
41a68f7c4a | ||
|
|
944d82028f | ||
|
|
379a6f1922 | ||
|
|
cede021400 | ||
|
|
99ad6005e8 | ||
|
|
dc9ee186f4 | ||
|
|
bb26979420 | ||
|
|
c6d20c876e | ||
|
|
3e3b902228 | ||
|
|
dfb45ba893 | ||
|
|
314efe2539 | ||
|
|
bbc680266b | ||
|
|
40232440b7 | ||
|
|
44f553b609 | ||
|
|
3b723282cb | ||
|
|
db4f12929e | ||
|
|
ea87912a74 | ||
|
|
ddcd916301 | ||
|
|
85a6a42bff | ||
|
|
ad017459d2 | ||
|
|
cfaf4b29d0 | ||
|
|
8d9e5d1258 | ||
|
|
212ec7e8e5 | ||
|
|
0f14065245 | ||
|
|
eb0f7e3d02 | ||
|
|
e9b04b8cfc | ||
|
|
253a0096f9 | ||
|
|
aa81c456bb | ||
|
|
ee5533f9bf | ||
|
|
416a40b0e6 | ||
|
|
418b316fab | ||
|
|
fd8ce7d779 | ||
|
|
ed34ddc04d | ||
|
|
581161ac34 | ||
|
|
69c9477783 | ||
|
|
98d6504d1d | ||
|
|
afb9980ad9 | ||
|
|
e3809f3111 | ||
|
|
fe7d1847b7 | ||
|
|
ad0394aebe | ||
|
|
af56065dd6 | ||
|
|
503422a72e | ||
|
|
329b434915 | ||
|
|
9362aede8f | ||
|
|
dfabe8db70 | ||
|
|
b0f3bb7a9a | ||
|
|
c7c8776371 | ||
|
|
7cef4f4e33 | ||
|
|
2c0520bc4b | ||
|
|
2118ecdf8e | ||
|
|
4302018437 | ||
|
|
236f42879c | ||
|
|
d329c92554 | ||
|
|
afbaf82395 | ||
|
|
a2ff2e6dd9 | ||
|
|
9f0b4d0000 | ||
|
|
649048c336 | ||
|
|
57ac9c2189 | ||
|
|
c4eedec9d5 | ||
|
|
2b9cb3a640 | ||
|
|
1081c45397 | ||
|
|
6c6201ab04 | ||
|
|
ea42275f06 | ||
|
|
5b567f3774 | ||
|
|
7f4a05debf | ||
|
|
e354a9bb48 | ||
|
|
b01bad7fad | ||
|
|
3b7f32db95 | ||
|
|
d3804d313c | ||
|
|
8746c3d9e0 | ||
|
|
c431698dba | ||
|
|
d138f7ce86 | ||
|
|
62a0c895b4 | ||
|
|
15d5261933 | ||
|
|
beb730a9e6 | ||
|
|
b1d05b6371 | ||
|
|
0c5212ae0b | ||
|
|
bc6616d511 | ||
|
|
2c82b3f8dd | ||
|
|
dc40fb5267 | ||
|
|
49df908dd3 | ||
|
|
fdc54b7455 | ||
|
|
607034a61e | ||
|
|
ee173ff7c9 | ||
|
|
761c77f5a2 | ||
|
|
f9e8428061 | ||
|
|
9d840088ac | ||
|
|
b133318b40 | ||
|
|
24e79a057c | ||
|
|
c66667c8c1 | ||
|
|
e8e7ddea45 | ||
|
|
6322944a5e | ||
|
|
510f9a1ae1 | ||
|
|
9b2a5f636a | ||
|
|
e1aa68a7bd | ||
|
|
cf5d4d4f8e | ||
|
|
bd7fabef1f | ||
|
|
1a38d515d7 | ||
|
|
0f9d9e13d1 | ||
|
|
c07b3fad64 | ||
|
|
9bf3063457 | ||
|
|
7bddf53223 | ||
|
|
0aa6109d4d | ||
|
|
cb1b13e95e | ||
|
|
f9876c9742 | ||
|
|
d28a2ec059 | ||
|
|
f226a277bf | ||
|
|
cce29209be | ||
|
|
efb6524fa0 | ||
|
|
a65f003ccc | ||
|
|
b485363006 | ||
|
|
7fb5266027 | ||
|
|
ae89dde969 | ||
|
|
12500be554 | ||
|
|
05b97c8c8e | ||
|
|
0402674ee7 | ||
|
|
269ef7f250 | ||
|
|
798225d9e1 | ||
|
|
b7d4db2446 | ||
|
|
3d9f1e02e5 | ||
|
|
74d937881e | ||
|
|
e72c759541 | ||
|
|
9cd69e46df | ||
|
|
5511cc170e | ||
|
|
41d5f4dbb5 | ||
|
|
f0de880136 | ||
|
|
44e2542e4a | ||
|
|
a5f3515ad8 | ||
|
|
a67ad44781 | ||
|
|
36134006c5 | ||
|
|
3215839524 | ||
|
|
c2218133bc | ||
|
|
7c3d8921b7 | ||
|
|
221ebdc1fb | ||
|
|
2c9b4770bc | ||
|
|
9867180202 | ||
|
|
8dec35ba67 | ||
|
|
74e07080d0 | ||
|
|
ab3004bcd5 | ||
|
|
1ea0c270df | ||
|
|
51fb82d6bf | ||
|
|
280b4d60f8 | ||
|
|
54bd94ad24 | ||
|
|
8840c1a2b7 | ||
|
|
d08fafb1c4 | ||
|
|
f3eb180f75 | ||
|
|
c0c3aac02e | ||
|
|
24a4302c52 | ||
|
|
e887a2eb3c | ||
|
|
8a94663df1 | ||
|
|
8062f96d6b | ||
|
|
cf59b40a1b | ||
|
|
53acbc8f18 | ||
|
|
36e57d16bd | ||
|
|
080aa78266 | ||
|
|
fc8998e377 | ||
|
|
d4a0ca35c7 | ||
|
|
f79305090b | ||
|
|
f133224683 | ||
|
|
83337d9fa8 | ||
|
|
84e1d15079 | ||
|
|
09a24ee97d | ||
|
|
99a3ccde71 | ||
|
|
8ca8a43968 | ||
|
|
9fa43394fe | ||
|
|
37590a495c | ||
|
|
ee106f9af8 | ||
|
|
23a98937b4 | ||
|
|
a0b63090e0 | ||
|
|
53a8bd2e3f | ||
|
|
e9962b98a7 | ||
|
|
a1ce6029c1 | ||
|
|
8c716184c1 | ||
|
|
5c888a0b47 | ||
|
|
498092a8ec | ||
|
|
caf6a3629d | ||
|
|
1ca96bbe5b | ||
|
|
cb5d0bca1c | ||
|
|
ef3d6f4a32 | ||
|
|
b470442a46 | ||
|
|
bf01c0b00e | ||
|
|
76e39af76f | ||
|
|
5b91cd0cc8 | ||
|
|
6255728e63 | ||
|
|
b657fc4f0b | ||
|
|
d294d51791 | ||
|
|
b35f8776e1 | ||
|
|
8ca78412ac | ||
|
|
33f933ba21 | ||
|
|
d70dd5123d | ||
|
|
15da702140 | ||
|
|
cd50c79ae4 | ||
|
|
3ebba5f32c | ||
|
|
9a423c388d | ||
|
|
daf9b8cfa9 | ||
|
|
b6a9220343 | ||
|
|
aeb017e029 | ||
|
|
a6174271aa | ||
|
|
517e0f8248 | ||
|
|
c1cb95db6f | ||
|
|
966e5f5337 | ||
|
|
f244ec8251 | ||
|
|
2b97f0fb43 | ||
|
|
af5e25cfb5 | ||
|
|
93cae68e94 | ||
|
|
6e6fe6a489 | ||
|
|
2c2436574d | ||
|
|
0cdca9ac2c | ||
|
|
4172be6bc8 | ||
|
|
d97b37a178 | ||
|
|
21334fa889 | ||
|
|
36a29f225b | ||
|
|
1e85c4379f | ||
|
|
470632b97a | ||
|
|
50044dd5e0 | ||
|
|
bc330b8ff3 | ||
|
|
7f36494eb2 | ||
|
|
85c48ba887 | ||
|
|
1e3935cbaf | ||
|
|
3fe491fcb2 | ||
|
|
66b608b2f9 | ||
|
|
4ee01d153b | ||
|
|
79e04fad9a | ||
|
|
6778bc04a3 | ||
|
|
d548f857a4 | ||
|
|
f99c59b6d5 | ||
|
|
0fd4983c66 | ||
|
|
240948b882 | ||
|
|
cf82e69bbe | ||
|
|
653e59a3d5 | ||
|
|
e342860ef1 | ||
|
|
569adae6a2 | ||
|
|
79fe885dcd | ||
|
|
a46f26e148 | ||
|
|
ca4b8b25f0 | ||
|
|
dad2c5fa52 | ||
|
|
8a08abcd35 | ||
|
|
b96befa250 | ||
|
|
8cc820668a | ||
|
|
ccb1ee04a5 | ||
|
|
d00936fb4e | ||
|
|
e84d5acd23 | ||
|
|
a8a4211d2b | ||
|
|
6907816af9 | ||
|
|
38db574de9 | ||
|
|
c7012528fc | ||
|
|
2162e5ff64 | ||
|
|
f40f5710f0 | ||
|
|
97940cae10 | ||
|
|
1555503493 | ||
|
|
1a035db4c8 | ||
|
|
df5b3693d6 | ||
|
|
b123719107 | ||
|
|
6ec109c15a | ||
|
|
dee1ff007d | ||
|
|
02b739743a | ||
|
|
f5361fdcb4 | ||
|
|
b86d5bd688 | ||
|
|
4bfffa69ff | ||
|
|
f9b4bcde38 | ||
|
|
aaecd6cc40 | ||
|
|
7e5f25e415 | ||
|
|
d8059d7f7d | ||
|
|
0f2b79a1d4 | ||
|
|
bb87642aee | ||
|
|
4a5b3eaa52 | ||
|
|
1b4e76797f | ||
|
|
58971182ca | ||
|
|
9427a85805 | ||
|
|
d145e818d0 | ||
|
|
e0fc8fe25b | ||
|
|
bb705d91a4 | ||
|
|
738fa286b2 | ||
|
|
1d1b8cc01f | ||
|
|
c357284e1a | ||
|
|
232596b83d | ||
|
|
1c1d558cc7 | ||
|
|
dffb16ed96 | ||
|
|
df8ce76bd6 | ||
|
|
4d18b62c54 | ||
|
|
8193731a82 | ||
|
|
1a6d062192 | ||
|
|
1ff13cdfc6 | ||
|
|
19e8cafe41 | ||
|
|
cbb5fe6007 | ||
|
|
c4fc30c243 | ||
|
|
117aa1dcc6 | ||
|
|
c550737a4f | ||
|
|
9e37ae3f5d | ||
|
|
c89ef8b84a | ||
|
|
23befdd13a | ||
|
|
58a83b0862 | ||
|
|
d5b4f7bb3e | ||
|
|
3cee4de39c | ||
|
|
f609a04671 | ||
|
|
7ffb6ffb0f | ||
|
|
3691856021 | ||
|
|
b5ca6a3add | ||
|
|
ecaa4846f1 | ||
|
|
787f9966ec | ||
|
|
013cfc77a1 | ||
|
|
16f7b01fec | ||
|
|
421c6565f9 | ||
|
|
d02deeefd8 | ||
|
|
235f5bb221 | ||
|
|
be3b4bd791 | ||
|
|
67d6447e12 | ||
|
|
fd9d7cb7bb | ||
|
|
3d6965ccbb | ||
|
|
707fa37160 | ||
|
|
7075b66bc6 | ||
|
|
9d55d71fdd | ||
|
|
cc9a20c4ab | ||
|
|
c39fafe6ec | ||
|
|
2a11725749 | ||
|
|
deed9eb18e | ||
|
|
50b49ebeb1 | ||
|
|
a74c6eef40 | ||
|
|
a3759c65e4 | ||
|
|
519760077b | ||
|
|
8390622f70 | ||
|
|
a04fbafcfd | ||
|
|
4fe8dee40f | ||
|
|
6fd80565c7 | ||
|
|
5ebd8ac7fe | ||
|
|
3cda1d03d9 | ||
|
|
d4eb02fac0 | ||
|
|
9c72d8a2b0 | ||
|
|
4f3127ccb8 | ||
|
|
877c27722f | ||
|
|
0dda8b58d1 | ||
|
|
e997d1ae5d | ||
|
|
3e2ef84d56 | ||
|
|
b2eccd6fe8 | ||
|
|
cc25a3b8c5 | ||
|
|
e93d945dba | ||
|
|
246e08096f | ||
|
|
860a52a736 | ||
|
|
18d8b29461 | ||
|
|
7af371701d | ||
|
|
5ccc95b76f | ||
|
|
cdb1d76484 | ||
|
|
9e423e949c | ||
|
|
e1ceb6892a | ||
|
|
40b8557608 | ||
|
|
92e107f52d | ||
|
|
2f6a87df98 | ||
|
|
2c29577e3c | ||
|
|
e72559bb27 | ||
|
|
6da1cf87b1 | ||
|
|
508b869773 | ||
|
|
59cc6843e6 | ||
|
|
f108fd2236 | ||
|
|
8081b59a02 | ||
|
|
26d180a50a | ||
|
|
10fe872c71 | ||
|
|
c74448f00d | ||
|
|
41ab7c44a0 | ||
|
|
3589a43682 | ||
|
|
ad70341139 | ||
|
|
ea93df571d | ||
|
|
bc21921001 | ||
|
|
07cbb62510 | ||
|
|
fc868cdda5 | ||
|
|
864a9ada57 | ||
|
|
f3e9d50d94 | ||
|
|
cdad0b998e | ||
|
|
64012d67a9 | ||
|
|
33d9d4dbf1 | ||
|
|
4c5e250ed8 | ||
|
|
1359fa14c1 | ||
|
|
c222a618a8 | ||
|
|
05c32e292e | ||
|
|
fb4f742416 | ||
|
|
276438b601 | ||
|
|
edec116ceb | ||
|
|
1aae1772ce | ||
|
|
a642395e9f | ||
|
|
70bfeddc90 | ||
|
|
e2a966443b | ||
|
|
0b13c3ca87 | ||
|
|
8b6766de79 | ||
|
|
c9371f812f | ||
|
|
e592d81b60 | ||
|
|
f2f50ccf75 | ||
|
|
75aed98c35 | ||
|
|
7f9818cfa2 | ||
|
|
679148449a | ||
|
|
bc00aeb10d | ||
|
|
4d258bd981 | ||
|
|
c465b0f2ff | ||
|
|
25160b671e | ||
|
|
20bfa42792 | ||
|
|
5a740e34c7 | ||
|
|
0aad599a9b | ||
|
|
b6c892a08a | ||
|
|
28d12e4e5d | ||
|
|
5d5e24a48e | ||
|
|
de598e55a6 | ||
|
|
0fd8392067 | ||
|
|
67ac2c5d9b | ||
|
|
7626fd7df3 | ||
|
|
db409fa69f | ||
|
|
5b8a8d356c | ||
|
|
d7e2ca3f10 | ||
|
|
387fbf6ab6 | ||
|
|
917eb88617 | ||
|
|
005827395d | ||
|
|
7f9fa64074 | ||
|
|
ab06a1c85c | ||
|
|
37048911ca | ||
|
|
2b7b6f71ee | ||
|
|
47d422bb8a | ||
|
|
c3ca77d6bf | ||
|
|
a3cd1e93be | ||
|
|
4cf8d81155 | ||
|
|
7774fe0ab3 | ||
|
|
f7db17f7d0 | ||
|
|
1106981827 | ||
|
|
1dac4158e9 | ||
|
|
18c5780485 | ||
|
|
e895052437 | ||
|
|
ade8d78c63 | ||
|
|
2e74b7177e | ||
|
|
6266e19623 | ||
|
|
c67aa49856 | ||
|
|
3a54089859 | ||
|
|
e2c447b8d0 | ||
|
|
843e12286f | ||
|
|
e60936e964 | ||
|
|
b9cfd89b80 | ||
|
|
de4224bbe4 | ||
|
|
ce91de76e4 | ||
|
|
acfce07aa0 | ||
|
|
81216189e4 | ||
|
|
2b26b380b6 | ||
|
|
1ba8d3060b | ||
|
|
f561007fb7 | ||
|
|
a63d5891e2 | ||
|
|
df38e954f4 | ||
|
|
ea532b4729 | ||
|
|
572d1b5920 | ||
|
|
e8fac6ca73 | ||
|
|
4de3fadb00 | ||
|
|
12f24aa8b4 | ||
|
|
911aa7774b | ||
|
|
1fb0e1e151 | ||
|
|
94bf279b5a | ||
|
|
37381b610d | ||
|
|
6d4df57393 | ||
|
|
3df01aaff0 | ||
|
|
4ee4f6f34b | ||
|
|
7953f7fa86 | ||
|
|
7a8df7795c | ||
|
|
aa493d3a9e | ||
|
|
72731f2c16 | ||
|
|
f680b6e82e | ||
|
|
ec22570eac | ||
|
|
198ead7c14 | ||
|
|
297a020abf | ||
|
|
473d989cde | ||
|
|
061bfce835 | ||
|
|
996e30e5d9 | ||
|
|
ecd2a14a15 | ||
|
|
8dfa8dc48c | ||
|
|
f7c183a429 | ||
|
|
473f86fcaa | ||
|
|
28353da61b | ||
|
|
efd49f07fd | ||
|
|
b8e183acc4 | ||
|
|
821c4b05fe | ||
|
|
4272d84fa2 | ||
|
|
e95505453e | ||
|
|
6dc34d19ea | ||
|
|
a670fbb33c | ||
|
|
98e6c119f5 | ||
|
|
c718a73d0a | ||
|
|
d74c817fd8 | ||
|
|
93d19db158 | ||
|
|
d7b611aa05 | ||
|
|
fc6008fdff | ||
|
|
a65d3119c0 | ||
|
|
51ecf4089b | ||
|
|
0c0fe8997b | ||
|
|
f86309dd03 | ||
|
|
c31fcb7134 | ||
|
|
91ec42f3f8 | ||
|
|
8f628296ad | ||
|
|
61bd3e8dd2 | ||
|
|
7263630967 | ||
|
|
16711c6f1a | ||
|
|
b2023f10b6 | ||
|
|
e915488a83 | ||
|
|
b2d629b50a | ||
|
|
125d4fa9dc | ||
|
|
527a1596f3 | ||
|
|
51d9f70f9e | ||
|
|
83727d48b5 | ||
|
|
8efc175340 | ||
|
|
6a6cb25d7e | ||
|
|
fd782ff568 | ||
|
|
dbfb469bad | ||
|
|
888a976fc0 | ||
|
|
2073730186 | ||
|
|
7a4a0c85c4 | ||
|
|
382ecb6bfe | ||
|
|
03694f7502 | ||
|
|
ee308a4994 | ||
|
|
a2b2336173 | ||
|
|
d7b1deb465 | ||
|
|
dd01639f57 | ||
|
|
525932fbf2 | ||
|
|
b1314349d7 | ||
|
|
9671f549a1 | ||
|
|
a1738a77ae | ||
|
|
689deb72bd | ||
|
|
84372cfad9 | ||
|
|
e429415ed4 | ||
|
|
7402be98b6 | ||
|
|
341b9725d4 | ||
|
|
8f164f7bc5 | ||
|
|
79c11a0458 | ||
|
|
4a4afc4639 | ||
|
|
ebdfd8046a | ||
|
|
d99e983236 | ||
|
|
1c6cfafba7 | ||
|
|
83d642b74f | ||
|
|
b1bc437d1b | ||
|
|
26989ce0ee | ||
|
|
e6356ce10c | ||
|
|
b92da0dc54 | ||
|
|
70e668bfcf | ||
|
|
8dd517870d | ||
|
|
f1753f36c8 | ||
|
|
3ea81d4a6f | ||
|
|
0df5cb1286 | ||
|
|
c43830b027 | ||
|
|
08624b8ef7 | ||
|
|
73b68927af | ||
|
|
bf699d3a79 | ||
|
|
f2e8d549ba | ||
|
|
4ffb6c0fea | ||
|
|
54776052a1 | ||
|
|
9c5eedf748 | ||
|
|
ca08956f77 | ||
|
|
aa74239f05 | ||
|
|
9e7018db8a | ||
|
|
cdea5b4873 | ||
|
|
4b0432423d | ||
|
|
2607580a09 | ||
|
|
ebd56bd8d5 | ||
|
|
ed1547e0cb | ||
|
|
5e388e21c8 | ||
|
|
4c89f9fba5 | ||
|
|
8e7958f78b | ||
|
|
579791e7bc | ||
|
|
595e28d335 | ||
|
|
0551f29de9 | ||
|
|
82b5c20050 | ||
|
|
ecaf1e9002 | ||
|
|
69ff621494 | ||
|
|
f32fe84c9b | ||
|
|
2ded352f3a | ||
|
|
c877a8528f | ||
|
|
d1754a9490 | ||
|
|
33a96a3dd7 | ||
|
|
cd889adfa0 | ||
|
|
77447ea6c3 | ||
|
|
fb05ee369f | ||
|
|
213da4fddd | ||
|
|
e78a09ebab | ||
|
|
7ccb871a45 | ||
|
|
9cc18bd7e6 | ||
|
|
8e2ecd17a9 | ||
|
|
78676dcff6 | ||
|
|
7847203d6e | ||
|
|
af3101c7f2 | ||
|
|
ec7e9f9228 | ||
|
|
ab5875c78f | ||
|
|
f6af4c29d4 | ||
|
|
996ad5bf26 | ||
|
|
096628e366 | ||
|
|
b432fb5efe | ||
|
|
c390c9d58e | ||
|
|
e25403c650 | ||
|
|
5c9a9e777c | ||
|
|
39d24fdeb7 | ||
|
|
bbb2b32816 | ||
|
|
0152639ef0 | ||
|
|
c43195efb6 | ||
|
|
17db918cba | ||
|
|
befd7fe63e | ||
|
|
de28391052 | ||
|
|
92f0aa23cc | ||
|
|
c8520fbe78 | ||
|
|
8ce60662f2 | ||
|
|
c5acbb6c7c | ||
|
|
4aca854b59 | ||
|
|
f7bf125037 | ||
|
|
c92ed07082 | ||
|
|
df0c3b3ea8 | ||
|
|
280b0429c3 | ||
|
|
cb22db675a | ||
|
|
bb21034972 | ||
|
|
ec5bc93576 | ||
|
|
f43fd7af79 | ||
|
|
a200fccba9 | ||
|
|
37dc31b815 | ||
|
|
1712ad08ae | ||
|
|
53f0c1eb4f | ||
|
|
c53adbbb84 | ||
|
|
e932aaaeaf | ||
|
|
b44d0c4bde | ||
|
|
917cfd7586 | ||
|
|
c7e6a73512 | ||
|
|
b7ba06fa5b | ||
|
|
51e205ce11 | ||
|
|
6984a4f4d4 | ||
|
|
4baecec7bf | ||
|
|
b262e7f9b8 | ||
|
|
b92c294059 | ||
|
|
07d03df8df | ||
|
|
9cc1d65280 | ||
|
|
893c1cab75 | ||
|
|
25d57350df | ||
|
|
eb68591396 | ||
|
|
6de9e230a0 | ||
|
|
668d29736c | ||
|
|
be667682f0 | ||
|
|
045bce5dfc | ||
|
|
3827479643 | ||
|
|
d41a195ee6 | ||
|
|
71d2fd37e2 | ||
|
|
66de981e91 | ||
|
|
375451785c | ||
|
|
a6af31a4cb | ||
|
|
94daf7bddc | ||
|
|
4eb73393bb | ||
|
|
f5c9764dd2 | ||
|
|
6dc25d796b | ||
|
|
0c07963a2e | ||
|
|
092d5dd608 | ||
|
|
e9bbd816de | ||
|
|
eb6f089a2a | ||
|
|
cb240081a8 | ||
|
|
9c57444adc | ||
|
|
7b8ebfa27e | ||
|
|
8ab05d6834 | ||
|
|
774df817fd | ||
|
|
18903a7dde | ||
|
|
7cfbfb7183 | ||
|
|
975d2bedb6 | ||
|
|
5c78394299 | ||
|
|
e33fe37a99 | ||
|
|
ea54cb6e9c | ||
|
|
08f0e28e55 | ||
|
|
2d4706e96e | ||
|
|
d30eef69b1 | ||
|
|
91909331b5 | ||
|
|
f31e213edc | ||
|
|
7b302d8c29 | ||
|
|
a1fae41051 | ||
|
|
b16bb409fc | ||
|
|
a77d24fdc6 | ||
|
|
eecf07cd12 | ||
|
|
06be88aef7 | ||
|
|
4c5b1574f1 | ||
|
|
de57cfd6ff | ||
|
|
2b24c15938 | ||
|
|
e874f94cf8 | ||
|
|
0a410141ae | ||
|
|
e356b29b4a | ||
|
|
bc4ce26cef | ||
|
|
ae66f720f5 | ||
|
|
9c15ba0c0b | ||
|
|
b3060065d9 | ||
|
|
a313b16704 | ||
|
|
b93b9dae88 | ||
|
|
277142fc4b | ||
|
|
18a508b29c | ||
|
|
cdfad864ae | ||
|
|
fb4453c18a | ||
|
|
b5ff55e538 | ||
|
|
81a9133261 | ||
|
|
ca6f9c4155 | ||
|
|
7569180cac | ||
|
|
eeec373728 | ||
|
|
0604e43813 | ||
|
|
27ade502ee | ||
|
|
3a7468ecac | ||
|
|
7b05dacb98 | ||
|
|
b73efb2c22 | ||
|
|
a06a5cadee | ||
|
|
3cd2d6fa5c | ||
|
|
ec839e9e96 | ||
|
|
6f2f9f6677 | ||
|
|
2082fdf84a | ||
|
|
894485190b | ||
|
|
87b2455dbb | ||
|
|
2e68967e02 | ||
|
|
71422a8549 | ||
|
|
9c69a5df69 | ||
|
|
9b24995990 | ||
|
|
142f06357f | ||
|
|
18ea68c23a | ||
|
|
4b2622d93b | ||
|
|
ae0193698e | ||
|
|
6b4a638415 | ||
|
|
4b3c9f5b35 | ||
|
|
6c69549ced | ||
|
|
5868750aba | ||
|
|
ab3052f642 | ||
|
|
53f4ccb809 | ||
|
|
077ae99438 | ||
|
|
fe8adf9eb8 | ||
|
|
c713d550c0 | ||
|
|
d19d89ea9d | ||
|
|
e8ec41fb0f | ||
|
|
7682ec029b | ||
|
|
03f726038e | ||
|
|
796945aad0 | ||
|
|
db02c13bf6 | ||
|
|
1ce9a87544 | ||
|
|
35e6e6347a | ||
|
|
54708233ac | ||
|
|
c679fd1924 | ||
|
|
9a79154d05 | ||
|
|
60872c91e6 | ||
|
|
afc4aedd4f | ||
|
|
f8ba899b87 | ||
|
|
52447e5d46 | ||
|
|
6794149ec8 | ||
|
|
a4772ae606 | ||
|
|
f30e09856c | ||
|
|
9b7f978e3e | ||
|
|
f17417219a | ||
|
|
d7f84aed8a | ||
|
|
deecbadda9 | ||
|
|
1431ffcebf | ||
|
|
1db1fee03a | ||
|
|
2f0116170d | ||
|
|
429225da80 | ||
|
|
39b77c0fca | ||
|
|
63e5790410 | ||
|
|
272e021c08 | ||
|
|
862ebd25cb | ||
|
|
5d8a85f7e7 | ||
|
|
5f30ccfbc3 | ||
|
|
71cab4fadc | ||
|
|
09ce430240 | ||
|
|
6be9109aaa | ||
|
|
67a7293e79 | ||
|
|
decb055df9 | ||
|
|
75674d819c | ||
|
|
35c430c8c9 | ||
|
|
94426de533 | ||
|
|
c4e27bf96c | ||
|
|
57bb1aa698 | ||
|
|
02270e9ccd | ||
|
|
1199c18b53 | ||
|
|
4f807eeb19 | ||
|
|
7c44b76477 | ||
|
|
c21633b1be | ||
|
|
1b05ba252c | ||
|
|
28474b08ee | ||
|
|
6f13b42279 | ||
|
|
8637587b82 | ||
|
|
f581dc4a56 | ||
|
|
693e9fc152 | ||
|
|
c595833883 | ||
|
|
7807b40322 | ||
|
|
b284970bac | ||
|
|
b46623ebef | ||
|
|
084c0a19bc | ||
|
|
3cee37388c | ||
|
|
a7969aef2c | ||
|
|
39c900c7e7 | ||
|
|
6e247c1583 | ||
|
|
87bf1dbc7f | ||
|
|
1f920ae6ba | ||
|
|
932e01b41a | ||
|
|
373f24c80f | ||
|
|
a548b289ef | ||
|
|
b168fc8cdd | ||
|
|
94845dcf98 | ||
|
|
1af6dff64e | ||
|
|
72de4f436e | ||
|
|
effda8291b | ||
|
|
7985e31020 | ||
|
|
866e0a618b | ||
|
|
a5ee61c117 | ||
|
|
08aad924d7 | ||
|
|
be02786dad | ||
|
|
949022db8c | ||
|
|
b1a090d4c0 | ||
|
|
39f3f150ed | ||
|
|
7e9f669421 | ||
|
|
6b769fb138 | ||
|
|
cc835a813e | ||
|
|
6103a4d13c | ||
|
|
69575dd4f3 | ||
|
|
bfcff3222c | ||
|
|
5adea789d0 | ||
|
|
78bbdca757 | ||
|
|
5cb82a49f8 | ||
|
|
9617737352 | ||
|
|
a251f6ad6c | ||
|
|
b61ca21a84 | ||
|
|
1a2a301aa2 |
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*.go text
|
||||||
|
*.md text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
@@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
- **Please check if the PR fulfills these requirements**
|
- **Please check if the PR fulfills these requirements**
|
||||||
|
|
||||||
* [ ] Cheatsheets are up-to-date (run `go run scripts/cheatsheet/main.go generate`)
|
* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
|
||||||
* [ ] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
|
* [ ] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
|
||||||
* [ ] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide)
|
* [ ] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide)
|
||||||
* [ ] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
|
* [ ] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
|
||||||
* [ ] Docs (specifically `docs/Config.md`) have been updated if necessary
|
* [ ] Docs have been updated if necessary
|
||||||
* [ ] You've read through your own file changes for silly mistakes etc
|
* [ ] You've read through your own file changes for silly mistakes etc
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
|
||||||
|
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for examples
|
||||||
|
-->
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
changelog:
|
||||||
|
exclude:
|
||||||
|
labels:
|
||||||
|
- ignore-for-release
|
||||||
|
categories:
|
||||||
|
- title: Features ✨
|
||||||
|
labels:
|
||||||
|
- feature
|
||||||
|
- title: Enhancements 🔥
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- title: Fixes 🔧
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- title: Maintenance ⚙️
|
||||||
|
labels:
|
||||||
|
- maintenance
|
||||||
|
- title: Docs 📖
|
||||||
|
labels:
|
||||||
|
- docs
|
||||||
|
- title: I18n 🌎
|
||||||
|
labels:
|
||||||
|
- i18n
|
||||||
|
- title: Other Changes
|
||||||
|
labels:
|
||||||
|
- "*"
|
||||||
@@ -3,22 +3,26 @@ name: Continuous Delivery
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'v*'
|
- "v*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Unshallow repo
|
- name: Unshallow repo
|
||||||
run: git fetch --prune --unshallow
|
run: git fetch --prune --unshallow
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Run goreleaser
|
- name: Run goreleaser
|
||||||
uses: goreleaser/goreleaser-action@v1
|
uses: goreleaser/goreleaser-action@v4
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: v1.17.2
|
||||||
|
args: release --clean
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
|
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
|
||||||
homebrew:
|
homebrew:
|
||||||
|
|||||||
+87
-72
@@ -1,7 +1,7 @@
|
|||||||
name: Continuous Integration
|
name: Continuous Integration
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: 1.18
|
GO_VERSION: 1.22
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -28,24 +28,22 @@ jobs:
|
|||||||
GOFLAGS: -mod=vendor
|
GOFLAGS: -mod=vendor
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Cache build
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
${{matrix.cache_path}}
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
|
|
||||||
restore-keys: |
|
|
||||||
${{runner.os}}-go-
|
|
||||||
- name: Test code
|
- name: Test code
|
||||||
# we're passing -short so that we skip the integration tests, which will be run in parallel below
|
# we're passing -short so that we skip the integration tests, which will be run in parallel below
|
||||||
run: |
|
run: |
|
||||||
go test ./... -short
|
mkdir -p /tmp/code_coverage
|
||||||
|
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
|
||||||
|
- name: Upload code coverage artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
|
||||||
|
path: /tmp/code_coverage
|
||||||
|
|
||||||
integration-tests:
|
integration-tests:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -63,11 +61,11 @@ jobs:
|
|||||||
GOFLAGS: -mod=vendor
|
GOFLAGS: -mod=vendor
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Restore Git cache
|
- name: Restore Git cache
|
||||||
if: matrix.git-version != 'latest'
|
if: matrix.git-version != 'latest'
|
||||||
id: cache-git-restore
|
id: cache-git-restore
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: ~/git-${{matrix.git-version}}
|
path: ~/git-${{matrix.git-version}}
|
||||||
key: ${{runner.os}}-git-${{matrix.git-version}}
|
key: ${{runner.os}}-git-${{matrix.git-version}}
|
||||||
@@ -84,28 +82,28 @@ jobs:
|
|||||||
run: sudo make -C "$HOME/git-${{matrix.git-version}}" -j install
|
run: sudo make -C "$HOME/git-${{matrix.git-version}}" -j install
|
||||||
- name: Save Git cache
|
- name: Save Git cache
|
||||||
if: steps.cache-git-restore.outputs.cache-hit != 'true' && matrix.git-version != 'latest'
|
if: steps.cache-git-restore.outputs.cache-hit != 'true' && matrix.git-version != 'latest'
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
path: ~/git-${{matrix.git-version}}
|
path: ~/git-${{matrix.git-version}}
|
||||||
key: ${{runner.os}}-git-${{matrix.git-version}}
|
key: ${{runner.os}}-git-${{matrix.git-version}}
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Cache build
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/go-build
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
|
|
||||||
restore-keys: |
|
|
||||||
${{runner.os}}-go-
|
|
||||||
- name: Print git version
|
- name: Print git version
|
||||||
run: git --version
|
run: git --version
|
||||||
- name: Test code
|
- name: Test code
|
||||||
|
env:
|
||||||
|
# See https://go.dev/blog/integration-test-coverage
|
||||||
|
LAZYGIT_GOCOVERDIR: /tmp/code_coverage
|
||||||
run: |
|
run: |
|
||||||
|
mkdir -p /tmp/code_coverage
|
||||||
./scripts/run_integration_tests.sh
|
./scripts/run_integration_tests.sh
|
||||||
|
- name: Upload code coverage artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
|
||||||
|
path: /tmp/code_coverage
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
@@ -113,20 +111,11 @@ jobs:
|
|||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Cache build
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/go-build
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-build
|
|
||||||
restore-keys: |
|
|
||||||
${{runner.os}}-go-
|
|
||||||
- name: Build linux binary
|
- name: Build linux binary
|
||||||
run: |
|
run: |
|
||||||
GOOS=linux go build
|
GOOS=linux go build
|
||||||
@@ -149,31 +138,23 @@ jobs:
|
|||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Cache build
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/go-build
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-build
|
|
||||||
restore-keys: |
|
|
||||||
${{runner.os}}-go-
|
|
||||||
- name: Check Cheatsheet
|
|
||||||
run: |
|
|
||||||
go run scripts/cheatsheet/main.go check
|
|
||||||
- name: Check Vendor Directory
|
- name: Check Vendor Directory
|
||||||
# ensure our vendor directory matches up with our go modules
|
# ensure our vendor directory matches up with our go modules
|
||||||
run: |
|
run: |
|
||||||
go mod vendor && git diff --exit-code || (echo "Unexpected change to vendor directory. Run 'go mod vendor' locally and commit the changes" && exit 1)
|
go mod vendor && git diff --exit-code || (echo "Unexpected change to vendor directory. Run 'go mod vendor' locally and commit the changes" && exit 1)
|
||||||
- name: Check Integration Test List
|
- name: Check go.mod file
|
||||||
# ensure our integration test list is up to date
|
# ensure our go.mod file is clean
|
||||||
run: |
|
run: |
|
||||||
go generate pkg/integration/tests/tests.go && git diff --exit-code || (echo "Integration test list not up to date. Run 'go generate pkg/integration/tests/tests.go' locally and commit the changes" && exit 1)
|
go mod tidy && git diff --exit-code || (echo "go.mod file is not clean. Run 'go mod tidy' locally and commit the changes" && exit 1)
|
||||||
|
- name: Check All Auto-Generated Files
|
||||||
|
# ensure all our auto-generated files are up to date
|
||||||
|
run: |
|
||||||
|
go generate ./... && git diff --quiet || (git status -s; echo "Auto-generated files not up to date. Run 'go generate ./...' locally and commit the changes" && exit 1)
|
||||||
shell: bash # needed so that we get "-o pipefail"
|
shell: bash # needed so that we get "-o pipefail"
|
||||||
- name: Check Filenames
|
- name: Check Filenames
|
||||||
run: scripts/check_filenames.sh
|
run: scripts/check_filenames.sh
|
||||||
@@ -183,24 +164,58 @@ jobs:
|
|||||||
GOFLAGS: -mod=vendor
|
GOFLAGS: -mod=vendor
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.x
|
go-version: 1.22.x
|
||||||
- name: Cache build
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/go-build
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
|
|
||||||
restore-keys: |
|
|
||||||
${{runner.os}}-go-
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
uses: golangci/golangci-lint-action@v3.1.0
|
uses: golangci/golangci-lint-action@v3.7.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: v1.58
|
||||||
- name: errors
|
- name: errors
|
||||||
run: golangci-lint run
|
run: golangci-lint run
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
check-required-label:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref != 'refs/heads/master'
|
||||||
|
steps:
|
||||||
|
- uses: mheap/github-action-required-labels@v5
|
||||||
|
with:
|
||||||
|
mode: exactly
|
||||||
|
count: 1
|
||||||
|
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n"
|
||||||
|
upload-coverage:
|
||||||
|
# List all jobs that produce coverage files
|
||||||
|
needs: [unit-tests, integration-tests]
|
||||||
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22.x
|
||||||
|
|
||||||
|
- name: Download all coverage artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: /tmp/code_coverage
|
||||||
|
|
||||||
|
- name: Combine coverage files
|
||||||
|
run: |
|
||||||
|
# Find all directories in /tmp/code_coverage and create a comma-separated list
|
||||||
|
COVERAGE_DIRS=$(find /tmp/code_coverage -mindepth 1 -maxdepth 1 -type d -printf '/tmp/code_coverage/%f,' | sed 's/,$//')
|
||||||
|
echo "Coverage directories: $COVERAGE_DIRS"
|
||||||
|
# Run the combine command with the generated list
|
||||||
|
go tool covdata textfmt -i=$COVERAGE_DIRS -o coverage.out
|
||||||
|
echo "Combined coverage:"
|
||||||
|
go tool cover -func coverage.out | tail -1 | awk '{print $3}'
|
||||||
|
|
||||||
|
- name: Upload to Codacy
|
||||||
|
run: |
|
||||||
|
CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
|
||||||
|
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
|
||||||
|
--force-coverage-parser go -r coverage.out
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout 🛎️
|
- name: Checkout 🛎️
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Generate Sponsors 💖
|
- name: Generate Sponsors 💖
|
||||||
uses: JamesIves/github-sponsors-readme-action@v1.0.8
|
uses: JamesIves/github-sponsors-readme-action@v1.2.2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.SPONSORS_TOKEN }}
|
token: ${{ secrets.SPONSORS_TOKEN }}
|
||||||
file: 'README.md'
|
file: "README.md"
|
||||||
if: ${{ github.repository == 'jesseduffield/lazygit' }}
|
if: ${{ github.repository == 'jesseduffield/lazygit' }}
|
||||||
|
|
||||||
- name: Commit and push if changed
|
- name: Create Pull Request 🚀
|
||||||
run: |-
|
uses: peter-evans/create-pull-request@v6
|
||||||
git diff
|
with:
|
||||||
git config --global user.email "actions@users.noreply.github.com"
|
commit-message: "README.md: Update Sponsors"
|
||||||
git config --global user.name "README-bot"
|
title: "README.md: Update Sponsors"
|
||||||
git add README.md
|
author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
|
||||||
git commit -m "Updated README.md" || exit 0
|
labels: "ignore-for-release"
|
||||||
git push
|
delete-branch: true
|
||||||
|
|||||||
+7
-4
@@ -6,9 +6,6 @@
|
|||||||
# Hidden
|
# Hidden
|
||||||
.*
|
.*
|
||||||
|
|
||||||
# TODO
|
|
||||||
TODO.*
|
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
*.notes
|
*.notes
|
||||||
|
|
||||||
@@ -22,6 +19,7 @@ lazygit.exe
|
|||||||
|
|
||||||
# Exceptions
|
# Exceptions
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.gitattributes
|
||||||
!.goreleaser.yml
|
!.goreleaser.yml
|
||||||
!.golangci.yml
|
!.golangci.yml
|
||||||
!.circleci/
|
!.circleci/
|
||||||
@@ -35,7 +33,12 @@ lazygit.exe
|
|||||||
|
|
||||||
test/git_server/data
|
test/git_server/data
|
||||||
|
|
||||||
test/results/**
|
test/_results/**
|
||||||
|
|
||||||
oryxBuildBinary
|
oryxBuildBinary
|
||||||
__debug_bin
|
__debug_bin
|
||||||
|
|
||||||
|
.worktrees
|
||||||
|
demo/output/*
|
||||||
|
|
||||||
|
coverage.out
|
||||||
|
|||||||
+13
-3
@@ -14,16 +14,26 @@ linters:
|
|||||||
- exhaustive
|
- exhaustive
|
||||||
- makezero
|
- makezero
|
||||||
- nakedret
|
- nakedret
|
||||||
# - goconst # TODO: enable and fix issues
|
- copyloopvar
|
||||||
fast: false
|
fast: false
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
|
copyloopvar:
|
||||||
|
# Check all assigning the loop variable to another variable.
|
||||||
|
# Default: false
|
||||||
|
# If true, an assignment like `a := x` will be detected as an error.
|
||||||
|
check-alias: true
|
||||||
exhaustive:
|
exhaustive:
|
||||||
default-signifies-exhaustive: true
|
default-signifies-exhaustive: true
|
||||||
|
staticcheck:
|
||||||
|
# SA1019 is for checking that we're not using fields marked as deprecated
|
||||||
|
# in a comment. It decides this in a loose way so I'm silencing it. Also because
|
||||||
|
# it's tripping on our own structs.
|
||||||
|
checks: ["all", "-SA1019"]
|
||||||
nakedret:
|
nakedret:
|
||||||
# the gods will judge me but I just don't like naked returns at all
|
# the gods will judge me but I just don't like naked returns at all
|
||||||
max-func-lines: 0
|
max-func-lines: 0
|
||||||
|
|
||||||
run:
|
run:
|
||||||
go: 1.18
|
go: '1.22'
|
||||||
|
timeout: 10m
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ builds:
|
|||||||
- amd64
|
- amd64
|
||||||
- arm
|
- arm
|
||||||
- arm64
|
- arm64
|
||||||
- 386
|
- '386'
|
||||||
# Default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}`.
|
# Default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}`.
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.buildSource=binaryRelease
|
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.buildSource=binaryRelease
|
||||||
|
|||||||
Vendored
+35
-10
@@ -7,11 +7,12 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "main.go",
|
"program": "main.go",
|
||||||
"args": ["--debug", "--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"],
|
"args": [
|
||||||
|
"--debug",
|
||||||
|
"--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"
|
||||||
|
],
|
||||||
|
"hideSystemGoroutines": true,
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"presentation": {
|
|
||||||
"hidden": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Tail Lazygit logs",
|
"name": "Tail Lazygit logs",
|
||||||
@@ -19,17 +20,41 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "main.go",
|
"program": "main.go",
|
||||||
"args": ["--logs", "--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"],
|
"args": [
|
||||||
|
"--logs",
|
||||||
|
"--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"
|
||||||
|
],
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"presentation": {
|
},
|
||||||
"hidden": true
|
{
|
||||||
}
|
"name": "Attach to a running Lazygit",
|
||||||
}
|
"type": "go",
|
||||||
|
"request": "attach",
|
||||||
|
"mode": "local",
|
||||||
|
"processId": "lazygit",
|
||||||
|
"hideSystemGoroutines": true,
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// To use this, first start an integration test with the "cli" runner and
|
||||||
|
// use the -debug option; e.g.
|
||||||
|
// $ make integration-test-cli -- -debug tag/reset.go
|
||||||
|
"name": "Attach to integration test runner",
|
||||||
|
"type": "go",
|
||||||
|
"request": "attach",
|
||||||
|
"mode": "local",
|
||||||
|
"processId": "test_lazygit",
|
||||||
|
"hideSystemGoroutines": true,
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"compounds": [
|
"compounds": [
|
||||||
{
|
{
|
||||||
"name": "Run with logs",
|
"name": "Run with logs",
|
||||||
"configurations": ["Tail Lazygit logs", "Debug Lazygit"],
|
"configurations": [
|
||||||
|
"Tail Lazygit logs",
|
||||||
|
"Debug Lazygit"
|
||||||
|
],
|
||||||
"stopAll": true
|
"stopAll": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"gopls": {
|
||||||
|
"formatting.gofumpt": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
+16
-25
@@ -10,6 +10,15 @@ before making a change.
|
|||||||
|
|
||||||
[This video](https://www.youtube.com/watch?v=kNavnhzZHtk) walks through the process of adding a small feature to lazygit. If you have no idea where to start, watching that video is a good first step.
|
[This video](https://www.youtube.com/watch?v=kNavnhzZHtk) walks through the process of adding a small feature to lazygit. If you have no idea where to start, watching that video is a good first step.
|
||||||
|
|
||||||
|
## Codebase guide
|
||||||
|
|
||||||
|
[This doc](./docs/dev/Codebase_Guide.md) explains:
|
||||||
|
* what the different packages in the codebase are for
|
||||||
|
* where important files live
|
||||||
|
* important concepts in the code
|
||||||
|
* how the event loop works
|
||||||
|
* other useful information
|
||||||
|
|
||||||
## All code changes happen through Pull Requests
|
## All code changes happen through Pull Requests
|
||||||
|
|
||||||
Pull requests are the best way to propose changes to the codebase. We actively
|
Pull requests are the best way to propose changes to the codebase. We actively
|
||||||
@@ -21,6 +30,8 @@ welcome your pull requests:
|
|||||||
4. Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
4. Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||||
5. Issue that pull request!
|
5. Issue that pull request!
|
||||||
|
|
||||||
|
Please do not raise pull request from your fork's master branch: make a feature branch instead. Lazygit maintainers will sometimes push changes to your branch when reviewing a PR and we often can't do this if you use your master branch.
|
||||||
|
|
||||||
If you've never written Go in your life, then join the club! Lazygit was the maintainer's first Go program, and most contributors have never used Go before. Go is widely considered an easy-to-learn language, so if you're looking for an open source project to gain dev experience, you've come to the right place.
|
If you've never written Go in your life, then join the club! Lazygit was the maintainer's first Go program, and most contributors have never used Go before. Go is widely considered an easy-to-learn language, so if you're looking for an open source project to gain dev experience, you've come to the right place.
|
||||||
|
|
||||||
## Running in a VSCode dev container
|
## Running in a VSCode dev container
|
||||||
@@ -97,6 +108,10 @@ To run gofumpt from your terminal go:
|
|||||||
go install mvdan.cc/gofumpt@latest && gofumpt -l -w .
|
go install mvdan.cc/gofumpt@latest && gofumpt -l -w .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Programming Font
|
||||||
|
|
||||||
|
Lazygit supports [Nerd Fonts](https://www.nerdfonts.com) to render certain icons. Sometimes we use some of these icons verbatim in string literals in the code (mainly in tests), so you need to set your development environment to use a nerd font to see these.
|
||||||
|
|
||||||
## Internationalisation
|
## Internationalisation
|
||||||
|
|
||||||
Boy that's a hard word to spell. Anyway, lazygit is translated into several languages within the pkg/i18n package. If you need to render text to the user, you should add a new field to the TranslationSet struct in `pkg/i18n/english.go` and add the actual content within the `EnglishTranslationSet()` method in the same file. Then you can access via `gui.Tr.YourNewText` (or `self.c.Tr.YourNewText`, etc). Although it is appreciated if you translate the text into other languages, it's not expected of you (google translate will likely do a bad job anyway!).
|
Boy that's a hard word to spell. Anyway, lazygit is translated into several languages within the pkg/i18n package. If you need to render text to the user, you should add a new field to the TranslationSet struct in `pkg/i18n/english.go` and add the actual content within the `EnglishTranslationSet()` method in the same file. Then you can access via `gui.Tr.YourNewText` (or `self.c.Tr.YourNewText`, etc). Although it is appreciated if you translate the text into other languages, it's not expected of you (google translate will likely do a bad job anyway!).
|
||||||
@@ -139,31 +154,7 @@ If you want to trigger a debug session from VSCode, you can use the following sn
|
|||||||
|
|
||||||
## Profiling
|
## Profiling
|
||||||
|
|
||||||
If you want to investigate what's contributing to CPU usage you can add the following to the top of the `main()` function in `main.go`
|
If you want to investigate what's contributing to CPU or memory usage, see [this separate document](docs/dev/Profiling.md).
|
||||||
|
|
||||||
```go
|
|
||||||
import "runtime/pprof"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
f, err := os.Create("cpu.prof")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("could not create CPU profile: ", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if err := pprof.StartCPUProfile(f); err != nil {
|
|
||||||
log.Fatal("could not start CPU profile: ", err)
|
|
||||||
}
|
|
||||||
defer pprof.StopCPUProfile()
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run lazygit, and afterwards, from your terminal, run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
go tool pprof --web cpu.prof
|
|
||||||
```
|
|
||||||
|
|
||||||
That should open an application which allows you to view the breakdown of CPU usage.
|
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -2,14 +2,14 @@
|
|||||||
# docker build -t lazygit .
|
# docker build -t lazygit .
|
||||||
# docker run -it lazygit:latest /bin/sh
|
# docker run -it lazygit:latest /bin/sh
|
||||||
|
|
||||||
FROM golang:1.18 as build
|
FROM golang:1.22 as build
|
||||||
WORKDIR /go/src/github.com/jesseduffield/lazygit/
|
WORKDIR /go/src/github.com/jesseduffield/lazygit/
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build
|
RUN CGO_ENABLED=0 GOOS=linux go build
|
||||||
|
|
||||||
FROM alpine:3.15
|
FROM alpine:3.19
|
||||||
RUN apk add --no-cache -U git xdg-utils
|
RUN apk add --no-cache -U git xdg-utils
|
||||||
WORKDIR /go/src/github.com/jesseduffield/lazygit/
|
WORKDIR /go/src/github.com/jesseduffield/lazygit/
|
||||||
COPY --from=build /go/src/github.com/jesseduffield/lazygit ./
|
COPY --from=build /go/src/github.com/jesseduffield/lazygit ./
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
.PHONY: all
|
||||||
|
all: build
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
go build -gcflags='all=-N -l'
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install:
|
||||||
|
go install
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: build
|
||||||
|
./lazygit
|
||||||
|
|
||||||
|
# Run `make run-debug` in one terminal tab and `make print-log` in another to view the program and its log output side by side
|
||||||
|
.PHONY: run-debug
|
||||||
|
run-debug:
|
||||||
|
go run main.go -debug
|
||||||
|
|
||||||
|
.PHONY: print-log
|
||||||
|
print-log:
|
||||||
|
go run main.go --logs
|
||||||
|
|
||||||
|
.PHONY: unit-test
|
||||||
|
unit-test:
|
||||||
|
go test ./... -short
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: unit-test integration-test-all
|
||||||
|
|
||||||
|
# Generate all our auto-generated files (test list, cheatsheets, maybe other things in the future)
|
||||||
|
.PHONY: generate
|
||||||
|
generate:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
.PHONY: format
|
||||||
|
format:
|
||||||
|
gofumpt -l -w .
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
|
||||||
|
.PHONY: integration-test-tui
|
||||||
|
integration-test-tui:
|
||||||
|
go run cmd/integration_test/main.go tui $(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
|
||||||
|
.PHONY: integration-test-cli
|
||||||
|
integration-test-cli:
|
||||||
|
go run cmd/integration_test/main.go cli $(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
|
||||||
|
.PHONY: integration-test-all
|
||||||
|
integration-test-all:
|
||||||
|
go test pkg/integration/clients/*.go
|
||||||
|
|
||||||
|
.PHONY: bump-gocui
|
||||||
|
bump-gocui:
|
||||||
|
scripts/bump_gocui.sh
|
||||||
|
|
||||||
|
.PHONY: bump-lazycore
|
||||||
|
bump-lazycore:
|
||||||
|
scripts/bump_lazycore.sh
|
||||||
|
|
||||||
|
.PHONY: record-demo
|
||||||
|
record-demo:
|
||||||
|
demo/record_demo.sh $(filter-out $@,$(MAKECMDGOALS))
|
||||||
|
|
||||||
|
.PHONY: vendor
|
||||||
|
vendor:
|
||||||
|
go mod vendor && go mod tidy
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
func saveLanguageFileToJson(tr *i18n.TranslationSet, filepath string) error {
|
||||||
|
jsonData, err := json.MarshalIndent(tr, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData = append(jsonData, '\n')
|
||||||
|
return os.WriteFile(filepath, jsonData, 0o644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := saveLanguageFileToJson(i18n.EnglishTranslationSet(), "en.json")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ Usage:
|
|||||||
> go run cmd/integration_test/main.go cli [--slow] [--sandbox] <test1> <test2> ...
|
> go run cmd/integration_test/main.go cli [--slow] [--sandbox] <test1> <test2> ...
|
||||||
If you pass no test names, it runs all tests
|
If you pass no test names, it runs all tests
|
||||||
Accepted environment variables:
|
Accepted environment variables:
|
||||||
KEY_PRESS_DELAY (e.g. 200): the number of milliseconds to wait between keypresses
|
INPUT_DELAY (e.g. 200): the number of milliseconds to wait between keypresses or mouse clicks
|
||||||
|
|
||||||
TUI mode:
|
TUI mode:
|
||||||
> go run cmd/integration_test/main.go tui
|
> go run cmd/integration_test/main.go tui
|
||||||
@@ -26,6 +26,29 @@ Usage:
|
|||||||
> go run cmd/integration_test/main.go help
|
> go run cmd/integration_test/main.go help
|
||||||
`
|
`
|
||||||
|
|
||||||
|
type flagInfo struct {
|
||||||
|
name string // name of the flag; can be used with "-" or "--"
|
||||||
|
flag *bool // a pointer to the variable that should be set to true when this flag is passed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes the args that you want to parse (excluding the program name and any
|
||||||
|
// subcommands), and returns the remaining args with the flags removed
|
||||||
|
func parseFlags(args []string, flags []flagInfo) []string {
|
||||||
|
outer:
|
||||||
|
for len(args) > 0 {
|
||||||
|
for _, f := range flags {
|
||||||
|
if args[0] == "-"+f.name || args[0] == "--"+f.name {
|
||||||
|
*f.flag = true
|
||||||
|
args = args[1:]
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
log.Fatal(usage)
|
log.Fatal(usage)
|
||||||
@@ -35,23 +58,26 @@ func main() {
|
|||||||
case "help":
|
case "help":
|
||||||
fmt.Println(usage)
|
fmt.Println(usage)
|
||||||
case "cli":
|
case "cli":
|
||||||
testNames := os.Args[2:]
|
|
||||||
slow := false
|
slow := false
|
||||||
sandbox := false
|
sandbox := false
|
||||||
// get the next arg if it's --slow
|
waitForDebugger := false
|
||||||
if len(os.Args) > 2 {
|
raceDetector := false
|
||||||
if os.Args[2] == "--slow" || os.Args[2] == "-slow" {
|
testNames := parseFlags(os.Args[2:], []flagInfo{
|
||||||
testNames = os.Args[3:]
|
{"slow", &slow},
|
||||||
slow = true
|
{"sandbox", &sandbox},
|
||||||
} else if os.Args[2] == "--sandbox" || os.Args[2] == "-sandbox" {
|
{"debug", &waitForDebugger},
|
||||||
testNames = os.Args[3:]
|
{"race", &raceDetector},
|
||||||
sandbox = true
|
})
|
||||||
}
|
clients.RunCLI(testNames, slow, sandbox, waitForDebugger, raceDetector)
|
||||||
}
|
|
||||||
|
|
||||||
clients.RunCLI(testNames, slow, sandbox)
|
|
||||||
case "tui":
|
case "tui":
|
||||||
clients.RunTUI()
|
raceDetector := false
|
||||||
|
remainingArgs := parseFlags(os.Args[2:], []flagInfo{
|
||||||
|
{"race", &raceDetector},
|
||||||
|
})
|
||||||
|
if len(remainingArgs) > 0 {
|
||||||
|
log.Fatal("tui only supports the -race argument.")
|
||||||
|
}
|
||||||
|
clients.RunTUI(raceDetector)
|
||||||
default:
|
default:
|
||||||
log.Fatal(usage)
|
log.Fatal(usage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
This directory contains stuff for recording lazygit demos.
|
||||||
|
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
# Specify a command to be executed
|
||||||
|
# like `/bin/bash -l`, `ls`, or any other commands
|
||||||
|
# the default is bash for Linux
|
||||||
|
# or powershell.exe for Windows
|
||||||
|
command: echo "YOU NEED TO SPECIFY YOUR OWN COMMAND WITH THE -d ARG"
|
||||||
|
|
||||||
|
# Specify the current working directory path
|
||||||
|
# the default is the current working directory path
|
||||||
|
cwd: null
|
||||||
|
|
||||||
|
# Export additional ENV variables
|
||||||
|
env:
|
||||||
|
recording: true
|
||||||
|
|
||||||
|
# Explicitly set the number of columns
|
||||||
|
# or use `auto` to take the current
|
||||||
|
# number of columns of your shell
|
||||||
|
cols: 120 # 100
|
||||||
|
|
||||||
|
# Explicitly set the number of rows
|
||||||
|
# or use `auto` to take the current
|
||||||
|
# number of rows of your shell
|
||||||
|
rows: 35 # 30
|
||||||
|
|
||||||
|
# Amount of times to repeat GIF
|
||||||
|
# If value is -1, play once
|
||||||
|
# If value is 0, loop indefinitely
|
||||||
|
# If value is a positive number, loop n times
|
||||||
|
repeat: 0
|
||||||
|
|
||||||
|
# Quality
|
||||||
|
# 1 - 100
|
||||||
|
# Higher quality seems to make no difference, but running it through
|
||||||
|
# gifsicle ends up with a much better compressed version.
|
||||||
|
quality: 100
|
||||||
|
|
||||||
|
# Delay between frames in ms
|
||||||
|
# If the value is `auto` use the actual recording delays
|
||||||
|
frameDelay: auto
|
||||||
|
|
||||||
|
# Maximum delay between frames in ms
|
||||||
|
# Ignored if the `frameDelay` isn't set to `auto`
|
||||||
|
# Set to `auto` to prevent limiting the max idle time
|
||||||
|
maxIdleTime: 2000
|
||||||
|
|
||||||
|
# The surrounding frame box
|
||||||
|
# The `type` can be null, window, floating, or solid`
|
||||||
|
# To hide the title use the value null
|
||||||
|
# Don't forget to add a backgroundColor style with a null as type
|
||||||
|
frameBox:
|
||||||
|
type: floating
|
||||||
|
title: Lazygit
|
||||||
|
style:
|
||||||
|
border: 0px black solid
|
||||||
|
backgroundColor: "#1d1d1d"
|
||||||
|
margin: -5px
|
||||||
|
|
||||||
|
# Add a watermark image to the rendered gif
|
||||||
|
# You need to specify an absolute path for
|
||||||
|
# the image on your machine or a URL, and you can also
|
||||||
|
# add your own CSS styles
|
||||||
|
watermark:
|
||||||
|
imagePath: null
|
||||||
|
style:
|
||||||
|
position: absolute
|
||||||
|
right: 15px
|
||||||
|
bottom: 15px
|
||||||
|
width: 100px
|
||||||
|
opacity: 0.9
|
||||||
|
|
||||||
|
# Cursor style can be one of
|
||||||
|
# `block`, `underline`, or `bar`
|
||||||
|
cursorStyle: block
|
||||||
|
|
||||||
|
# Font family
|
||||||
|
# You can use any font that is installed on your machine
|
||||||
|
# in CSS-like syntax
|
||||||
|
# Download from:
|
||||||
|
# https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/DejaVuSansMono.zip
|
||||||
|
# Not using the mono font because it makes icons too small.
|
||||||
|
fontFamily: "DejaVuSansM Nerd Font"
|
||||||
|
|
||||||
|
# The size of the font
|
||||||
|
fontSize: 8
|
||||||
|
|
||||||
|
# The height of lines
|
||||||
|
lineHeight: 1
|
||||||
|
|
||||||
|
# The spacing between letters
|
||||||
|
letterSpacing: 0
|
||||||
|
|
||||||
|
# Theme
|
||||||
|
theme:
|
||||||
|
background: "transparent"
|
||||||
|
foreground: "#dddad6"
|
||||||
|
cursor: "#c7c7c7"
|
||||||
|
black: "#7a7a7a"
|
||||||
|
red: "#fc4384"
|
||||||
|
green: "#b3e33b"
|
||||||
|
yellow: "#ffa727"
|
||||||
|
blue: "#102895"
|
||||||
|
magenta: "#c930c7"
|
||||||
|
cyan: "#00c5c7"
|
||||||
|
white: "#c7c7c7"
|
||||||
|
brightBlack: "#676767"
|
||||||
|
brightRed: "#ff7fac"
|
||||||
|
brightGreen: "#c8ed71"
|
||||||
|
brightYellow: "#ebdf86"
|
||||||
|
brightBlue: "#6871ff"
|
||||||
|
brightMagenta: "#ff76ff"
|
||||||
|
brightCyan: "#5ffdff"
|
||||||
|
brightWhite: "#fffefe"
|
||||||
Executable
+81
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TYPE=$1
|
||||||
|
TEST=$2
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $0 [gif|mp4] <test path>"
|
||||||
|
echo "e.g. using full path: $0 gif pkg/integration/tests/demo/nuke_working_tree.go"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$#" -ne 2 ]
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$TYPE" != "gif" ] && [ "$TYPE" != "mp4" ]
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$TEST" ]
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
WORKTREE_PATH=$(git worktree list | grep assets | awk '{print $1}')
|
||||||
|
|
||||||
|
if [ -z "$WORKTREE_PATH" ]
|
||||||
|
then
|
||||||
|
echo "Could not find assets worktree. You'll need to create a worktree for the assets branch using the following command:"
|
||||||
|
echo "git worktree add .worktrees/assets assets"
|
||||||
|
echo "The assets branch has no shared history with the main branch: it exists to store assets which are too large to store in the main branch."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_DIR="$WORKTREE_PATH/demo"
|
||||||
|
|
||||||
|
if ! command -v terminalizer &> /dev/null
|
||||||
|
then
|
||||||
|
echo "terminalizer could not be found"
|
||||||
|
echo "Install it with: npm install -g terminalizer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v "gifsicle" &> /dev/null
|
||||||
|
then
|
||||||
|
echo "gifsicle could not be found"
|
||||||
|
echo "Install it with: npm install -g gifsicle"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get last part of the test path and set that as the output name
|
||||||
|
# example test path: pkg/integration/tests/01_basic_test.go
|
||||||
|
# For that we want: NAME=01_basic_test
|
||||||
|
NAME=$(echo "$TEST" | sed -e 's/.*\///' | sed -e 's/\..*//')
|
||||||
|
|
||||||
|
# Add the demo to the tests list (if missing) so that it can be run
|
||||||
|
go generate pkg/integration/tests/tests.go
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
# First we record the demo into a yaml representation
|
||||||
|
terminalizer -c demo/config.yml record --skip-sharing -d "go run cmd/integration_test/main.go cli --slow $TEST" "$OUTPUT_DIR/$NAME"
|
||||||
|
# Then we render it into a gif
|
||||||
|
terminalizer render "$OUTPUT_DIR/$NAME" -o "$OUTPUT_DIR/$NAME.gif"
|
||||||
|
|
||||||
|
# Then we convert it to either an mp4 or gif based on the command line argument
|
||||||
|
if [ "$TYPE" = "mp4" ]
|
||||||
|
then
|
||||||
|
COMPRESSED_PATH="$OUTPUT_DIR/$NAME.mp4"
|
||||||
|
ffmpeg -y -i "$OUTPUT_DIR/$NAME.gif" -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" "$COMPRESSED_PATH"
|
||||||
|
else
|
||||||
|
COMPRESSED_PATH="$OUTPUT_DIR/$NAME-compressed.gif"
|
||||||
|
gifsicle --colors 256 --use-col=web -O3 < "$OUTPUT_DIR/$NAME.gif" > "$COMPRESSED_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Demo recorded to $COMPRESSED_PATH"
|
||||||
+610
-215
@@ -3,8 +3,8 @@
|
|||||||
Default path for the config file:
|
Default path for the config file:
|
||||||
|
|
||||||
- Linux: `~/.config/lazygit/config.yml`
|
- Linux: `~/.config/lazygit/config.yml`
|
||||||
- MacOS: `~/Library/Application Support/lazygit/config.yml`
|
- MacOS: `~/Library/Application\ Support/lazygit/config.yml`
|
||||||
- Windows: `%APPDATA%\lazygit\config.yml`
|
- Windows: `%LOCALAPPDATA%\lazygit\config.yml` (default location, but it will also be found in `%APPDATA%\lazygit\config.yml`
|
||||||
|
|
||||||
For old installations (slightly embarrassing: I didn't realise at the time that you didn't need to supply a vendor name to the path so I just used my name):
|
For old installations (slightly embarrassing: I didn't realise at the time that you didn't need to supply a vendor name to the path so I just used my name):
|
||||||
|
|
||||||
@@ -16,245 +16,600 @@ If you want to change the config directory:
|
|||||||
|
|
||||||
- MacOS: `export XDG_CONFIG_HOME="$HOME/.config"`
|
- MacOS: `export XDG_CONFIG_HOME="$HOME/.config"`
|
||||||
|
|
||||||
## Default
|
JSON schema is available for `config.yml` so that IntelliSense in Visual Studio Code (completion and error checking) is automatically enabled when the [YAML Red Hat][yaml] extension is installed. However, note that automatic schema detection only works if your config file is in one of the standard paths mentioned above. If you override the path to the file, you can still make IntelliSense work by adding
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
# yaml-language-server: $schema=https://raw.githubusercontent.com/jesseduffield/lazygit/master/schema/config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
to the top of your config file or via [Visual Studio Code settings.json config][settings].
|
||||||
|
|
||||||
|
[yaml]: https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml
|
||||||
|
[settings]: https://github.com/redhat-developer/vscode-yaml#associating-a-schema-to-a-glob-pattern-via-yamlschemas
|
||||||
|
|
||||||
|
## Default
|
||||||
|
|
||||||
|
<!-- START CONFIG YAML: AUTOMATICALLY GENERATED with `go generate ./..., DO NOT UPDATE MANUALLY -->
|
||||||
|
```yaml
|
||||||
|
# Config relating to the Lazygit UI
|
||||||
gui:
|
gui:
|
||||||
# stuff relating to the UI
|
# The number of lines you scroll by when scrolling the main window
|
||||||
windowSize: 'normal' # one of 'normal' | 'half' | 'full' default is 'normal'
|
scrollHeight: 2
|
||||||
scrollHeight: 2 # how many lines you scroll by
|
|
||||||
scrollPastBottom: true # enable scrolling past the bottom
|
# If true, allow scrolling past the bottom of the content in the main window
|
||||||
sidePanelWidth: 0.3333 # number from 0 to 1
|
scrollPastBottom: true
|
||||||
|
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#scroll-off-margin
|
||||||
|
scrollOffMargin: 2
|
||||||
|
|
||||||
|
# One of: 'margin' (default) | 'jump'
|
||||||
|
scrollOffBehavior: margin
|
||||||
|
|
||||||
|
# If true, capture mouse events.
|
||||||
|
# When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
|
||||||
|
mouseEvents: true
|
||||||
|
|
||||||
|
# If true, do not show a warning when discarding changes in the staging view.
|
||||||
|
skipDiscardChangeWarning: false
|
||||||
|
|
||||||
|
# If true, do not show warning when applying/popping the stash
|
||||||
|
skipStashWarning: false
|
||||||
|
|
||||||
|
# If true, do not show a warning when attempting to commit without any staged files; instead stage all unstaged files.
|
||||||
|
skipNoStagedFilesWarning: false
|
||||||
|
|
||||||
|
# If true, do not show a warning when rewording a commit via an external editor
|
||||||
|
skipRewordInEditorWarning: false
|
||||||
|
|
||||||
|
# Fraction of the total screen width to use for the left side section. You may want to pick a small number (e.g. 0.2) if you're using a narrow screen, so that you can see more of the main section.
|
||||||
|
# Number from 0 to 1.0.
|
||||||
|
sidePanelWidth: 0.3333
|
||||||
|
|
||||||
|
# If true, increase the height of the focused side window; creating an accordion effect.
|
||||||
expandFocusedSidePanel: false
|
expandFocusedSidePanel: false
|
||||||
mainPanelSplitMode: 'flexible' # one of 'horizontal' | 'flexible' | 'vertical'
|
|
||||||
language: 'auto' # one of 'auto' | 'en' | 'zh' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
|
# The weight of the expanded side panel, relative to the other panels. 2 means
|
||||||
timeFormat: '02 Jan 06' # https://pkg.go.dev/time#Time.Format
|
# twice as tall as the other panels. Only relevant if `expandFocusedSidePanel` is true.
|
||||||
shortTimeFormat: '3:04PM'
|
expandedSidePanelWeight: 2
|
||||||
|
|
||||||
|
# Sometimes the main window is split in two (e.g. when the selected file has both staged and unstaged changes). This setting controls how the two sections are split.
|
||||||
|
# Options are:
|
||||||
|
# - 'horizontal': split the window horizontally
|
||||||
|
# - 'vertical': split the window vertically
|
||||||
|
# - 'flexible': (default) split the window horizontally if the window is wide enough, otherwise split vertically
|
||||||
|
mainPanelSplitMode: flexible
|
||||||
|
|
||||||
|
# How the window is split when in half screen mode (i.e. after hitting '+' once).
|
||||||
|
# Possible values:
|
||||||
|
# - 'left': split the window horizontally (side panel on the left, main view on the right)
|
||||||
|
# - 'top': split the window vertically (side panel on top, main view below)
|
||||||
|
enlargedSideViewLocation: left
|
||||||
|
|
||||||
|
# One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
|
||||||
|
language: auto
|
||||||
|
|
||||||
|
# Format used when displaying time e.g. commit time.
|
||||||
|
# Uses Go's time format syntax: https://pkg.go.dev/time#Time.Format
|
||||||
|
timeFormat: 02 Jan 06
|
||||||
|
|
||||||
|
# Format used when displaying time if the time is less than 24 hours ago.
|
||||||
|
# Uses Go's time format syntax: https://pkg.go.dev/time#Time.Format
|
||||||
|
shortTimeFormat: 3:04PM
|
||||||
|
|
||||||
|
# Config relating to colors and styles.
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#color-attributes
|
||||||
theme:
|
theme:
|
||||||
|
# Border color of focused window
|
||||||
activeBorderColor:
|
activeBorderColor:
|
||||||
- green
|
- green
|
||||||
- bold
|
- bold
|
||||||
|
|
||||||
|
# Border color of non-focused windows
|
||||||
inactiveBorderColor:
|
inactiveBorderColor:
|
||||||
- white
|
- default
|
||||||
|
|
||||||
|
# Border color of focused window when searching in that window
|
||||||
searchingActiveBorderColor:
|
searchingActiveBorderColor:
|
||||||
- cyan
|
- cyan
|
||||||
- bold
|
- bold
|
||||||
|
|
||||||
|
# Color of keybindings help text in the bottom line
|
||||||
optionsTextColor:
|
optionsTextColor:
|
||||||
- blue
|
- blue
|
||||||
|
|
||||||
|
# Background color of selected line.
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#highlighting-the-selected-line
|
||||||
selectedLineBgColor:
|
selectedLineBgColor:
|
||||||
- blue # set to `default` to have no background colour
|
|
||||||
selectedRangeBgColor:
|
|
||||||
- blue
|
- blue
|
||||||
cherryPickedCommitBgColor:
|
|
||||||
- cyan
|
# Background color of selected line when view doesn't have focus.
|
||||||
|
inactiveViewSelectedLineBgColor:
|
||||||
|
- bold
|
||||||
|
|
||||||
|
# Foreground color of copied commit
|
||||||
cherryPickedCommitFgColor:
|
cherryPickedCommitFgColor:
|
||||||
- blue
|
- blue
|
||||||
|
|
||||||
|
# Background color of copied commit
|
||||||
|
cherryPickedCommitBgColor:
|
||||||
|
- cyan
|
||||||
|
|
||||||
|
# Foreground color of marked base commit (for rebase)
|
||||||
|
markedBaseCommitFgColor:
|
||||||
|
- blue
|
||||||
|
|
||||||
|
# Background color of marked base commit (for rebase)
|
||||||
|
markedBaseCommitBgColor:
|
||||||
|
- yellow
|
||||||
|
|
||||||
|
# Color for file with unstaged changes
|
||||||
unstagedChangesColor:
|
unstagedChangesColor:
|
||||||
- red
|
- red
|
||||||
|
|
||||||
|
# Default text color
|
||||||
defaultFgColor:
|
defaultFgColor:
|
||||||
- default
|
- default
|
||||||
|
|
||||||
|
# Config relating to the commit length indicator
|
||||||
commitLength:
|
commitLength:
|
||||||
|
# If true, show an indicator of commit message length
|
||||||
show: true
|
show: true
|
||||||
mouseEvents: true
|
|
||||||
skipDiscardChangeWarning: false
|
# If true, show the '5 of 20' footer at the bottom of list views
|
||||||
skipStashWarning: false
|
showListFooter: true
|
||||||
showFileTree: true # for rendering changes files in a tree format
|
|
||||||
showListFooter: true # for seeing the '5 of 20' message in list panels
|
# If true, display the files in the file views as a tree. If false, display the files as a flat list.
|
||||||
|
# This can be toggled from within Lazygit with the '~' key, but that will not change the default.
|
||||||
|
showFileTree: true
|
||||||
|
|
||||||
|
# If true, show a random tip in the command log when Lazygit starts
|
||||||
showRandomTip: true
|
showRandomTip: true
|
||||||
showBranchCommitHash: false # show commit hashes alongside branch names
|
|
||||||
experimentalShowBranchHeads: false # visualize branch heads with (*) in commits list
|
# If true, show the command log
|
||||||
showBottomLine: true # for hiding the bottom information line (unless it has important information to tell you)
|
|
||||||
showCommandLog: true
|
showCommandLog: true
|
||||||
showIcons: false # deprecated: use nerdFontsVersion instead
|
|
||||||
nerdFontsVersion: "" # nerd fonts version to use ("2" or "3"); empty means don't show nerd font icons
|
# If true, show the bottom line that contains keybinding info and useful buttons. If false, this line will be hidden except to display a loader for an in-progress action.
|
||||||
|
showBottomLine: true
|
||||||
|
|
||||||
|
# If true, show jump-to-window keybindings in window titles.
|
||||||
|
showPanelJumps: true
|
||||||
|
|
||||||
|
# Deprecated: use nerdFontsVersion instead
|
||||||
|
showIcons: false
|
||||||
|
|
||||||
|
# Nerd fonts version to use.
|
||||||
|
# One of: '2' | '3' | empty string (default)
|
||||||
|
# If empty, do not show icons.
|
||||||
|
nerdFontsVersion: ""
|
||||||
|
|
||||||
|
# If true (default), file icons are shown in the file views. Only relevant if NerdFontsVersion is not empty.
|
||||||
|
showFileIcons: true
|
||||||
|
|
||||||
|
# Length of author name in (non-expanded) commits view. 2 means show initials only.
|
||||||
|
commitAuthorShortLength: 2
|
||||||
|
|
||||||
|
# Length of author name in expanded commits view. 2 means show initials only.
|
||||||
|
commitAuthorLongLength: 17
|
||||||
|
|
||||||
|
# Length of commit hash in commits view. 0 shows '*' if NF icons aren't on.
|
||||||
|
commitHashLength: 8
|
||||||
|
|
||||||
|
# If true, show commit hashes alongside branch names in the branches view.
|
||||||
|
showBranchCommitHash: false
|
||||||
|
|
||||||
|
# Whether to show the divergence from the base branch in the branches view.
|
||||||
|
# One of: 'none' | 'onlyArrow' | 'arrowAndNumber'
|
||||||
|
showDivergenceFromBaseBranch: none
|
||||||
|
|
||||||
|
# Height of the command log view
|
||||||
commandLogSize: 8
|
commandLogSize: 8
|
||||||
splitDiff: 'auto' # one of 'auto' | 'always'
|
|
||||||
skipRewordInEditorWarning: false # for skipping the confirmation before launching the reword editor
|
# Whether to split the main window when viewing file changes.
|
||||||
border: 'single' # one of 'single' | 'double' | 'rounded' | 'hidden'
|
# One of: 'auto' | 'always'
|
||||||
|
# If 'auto', only split the main window when a file has both staged and unstaged changes
|
||||||
|
splitDiff: auto
|
||||||
|
|
||||||
|
# Default size for focused window. Window size can be changed from within Lazygit with '+' and '_' (but this won't change the default).
|
||||||
|
# One of: 'normal' (default) | 'half' | 'full'
|
||||||
|
windowSize: normal
|
||||||
|
|
||||||
|
# Window border style.
|
||||||
|
# One of 'rounded' (default) | 'single' | 'double' | 'hidden'
|
||||||
|
border: rounded
|
||||||
|
|
||||||
|
# If true, show a seriously epic explosion animation when nuking the working tree.
|
||||||
|
animateExplosion: true
|
||||||
|
|
||||||
|
# Whether to stack UI components on top of each other.
|
||||||
|
# One of 'auto' (default) | 'always' | 'never'
|
||||||
|
portraitMode: auto
|
||||||
|
|
||||||
|
# How things are filtered when typing '/'.
|
||||||
|
# One of 'substring' (default) | 'fuzzy'
|
||||||
|
filterMode: substring
|
||||||
|
|
||||||
|
# Config relating to the spinner.
|
||||||
|
spinner:
|
||||||
|
# The frames of the spinner animation.
|
||||||
|
frames:
|
||||||
|
- '|'
|
||||||
|
- /
|
||||||
|
- '-'
|
||||||
|
- \
|
||||||
|
|
||||||
|
# The "speed" of the spinner in milliseconds.
|
||||||
|
rate: 50
|
||||||
|
|
||||||
|
# Status panel view.
|
||||||
|
# One of 'dashboard' (default) | 'allBranchesLog'
|
||||||
|
statusPanelView: dashboard
|
||||||
|
|
||||||
|
# Config relating to git
|
||||||
git:
|
git:
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md
|
||||||
paging:
|
paging:
|
||||||
|
# Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never'
|
||||||
colorArg: always
|
colorArg: always
|
||||||
|
|
||||||
|
# e.g.
|
||||||
|
# diff-so-fancy
|
||||||
|
# delta --dark --paging=never
|
||||||
|
# ydiff -p cat -s --wrap --width={{columnWidth}}
|
||||||
|
pager: ""
|
||||||
|
|
||||||
|
# If true, Lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
|
||||||
useConfig: false
|
useConfig: false
|
||||||
|
|
||||||
|
# e.g. 'difft --color=always'
|
||||||
|
externalDiffCommand: ""
|
||||||
|
|
||||||
|
# Config relating to committing
|
||||||
commit:
|
commit:
|
||||||
|
# If true, pass '--signoff' flag when committing
|
||||||
signOff: false
|
signOff: false
|
||||||
verbose: default # one of 'default' | 'always' | 'never'
|
|
||||||
|
# Automatic WYSIWYG wrapping of the commit message as you type
|
||||||
|
autoWrapCommitMessage: true
|
||||||
|
|
||||||
|
# If autoWrapCommitMessage is true, the width to wrap to
|
||||||
|
autoWrapWidth: 72
|
||||||
|
|
||||||
|
# Config relating to merging
|
||||||
merging:
|
merging:
|
||||||
# only applicable to unix users
|
# If true, run merges in a subprocess so that if a commit message is required, Lazygit will not hang
|
||||||
|
# Only applicable to unix users.
|
||||||
manualCommit: false
|
manualCommit: false
|
||||||
# extra args passed to `git merge`, e.g. --no-ff
|
|
||||||
args: ''
|
# Extra args passed to `git merge`, e.g. --no-ff
|
||||||
log:
|
args: ""
|
||||||
# one of date-order, author-date-order, topo-order or default.
|
|
||||||
# topo-order makes it easier to read the git log graph, but commits may not
|
# The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders.
|
||||||
# appear chronologically. See https://git-scm.com/docs/git-log#_commit_ordering
|
squashMergeMessage: Squash merge {{selectedRef}} into {{currentBranch}}
|
||||||
order: 'topo-order'
|
|
||||||
# one of always, never, when-maximised
|
# list of branches that are considered 'main' branches, used when displaying commits
|
||||||
# this determines whether the git graph is rendered in the commits panel
|
mainBranches:
|
||||||
showGraph: 'when-maximised'
|
- master
|
||||||
# displays the whole git graph by default in the commits panel (equivalent to passing the `--all` argument to `git log`)
|
- main
|
||||||
showWholeGraph: false
|
|
||||||
|
# Prefix to use when skipping hooks. E.g. if set to 'WIP', then pre-commit hooks will be skipped when the commit message starts with 'WIP'
|
||||||
skipHookPrefix: WIP
|
skipHookPrefix: WIP
|
||||||
# The main branches. We colour commits green if they belong to one of these branches,
|
|
||||||
# so that you can easily see which commits are unique to your branch (coloured in yellow)
|
# If true, periodically fetch from remote
|
||||||
mainBranches: [master, main]
|
|
||||||
autoFetch: true
|
autoFetch: true
|
||||||
|
|
||||||
|
# If true, periodically refresh files and submodules
|
||||||
autoRefresh: true
|
autoRefresh: true
|
||||||
fetchAll: true # Pass --all flag when running git fetch. Set to false to fetch only origin (or the current branch's upstream remote if there is one)
|
|
||||||
branchLogCmd: 'git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --'
|
# If true, pass the --all arg to git fetch
|
||||||
allBranchesLogCmd: 'git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium'
|
fetchAll: true
|
||||||
overrideGpg: false # prevents lazygit from spawning a separate process when using GPG
|
|
||||||
|
# Command used when displaying the current branch git log in the main window
|
||||||
|
branchLogCmd: git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --
|
||||||
|
|
||||||
|
# Command used to display git log of all branches in the main window.
|
||||||
|
# Deprecated: User `allBranchesLogCmds` instead.
|
||||||
|
allBranchesLogCmd: git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium
|
||||||
|
|
||||||
|
# If true, do not spawn a separate process when using GPG
|
||||||
|
overrideGpg: false
|
||||||
|
|
||||||
|
# If true, do not allow force pushes
|
||||||
disableForcePushing: false
|
disableForcePushing: false
|
||||||
|
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
|
||||||
|
commitPrefix:
|
||||||
|
# pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use "^\\w+\\/(\\w+-\\w+).*"
|
||||||
|
pattern: ""
|
||||||
|
|
||||||
|
# Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use "[$1] "
|
||||||
|
replace: ""
|
||||||
|
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
|
||||||
|
branchPrefix: ""
|
||||||
|
|
||||||
|
# If true, parse emoji strings in commit messages e.g. render :rocket: as 🚀
|
||||||
|
# (This should really be under 'gui', not 'git')
|
||||||
parseEmoji: false
|
parseEmoji: false
|
||||||
diffContextSize: 3 # how many lines of context are shown around a change in diffs
|
|
||||||
os:
|
# Config for showing the log in the commits view
|
||||||
editPreset: '' # see 'Configuring File Editing' section
|
log:
|
||||||
edit: ''
|
# One of: 'date-order' | 'author-date-order' | 'topo-order' | 'default'
|
||||||
editAtLine: ''
|
# 'topo-order' makes it easier to read the git log graph, but commits may not
|
||||||
editAtLineAndWait: ''
|
# appear chronologically. See https://git-scm.com/docs/
|
||||||
open: ''
|
#
|
||||||
openLink: ''
|
# Deprecated: Configure this with `Log menu -> Commit sort order` (<c-l> in the commits window by default).
|
||||||
refresher:
|
order: topo-order
|
||||||
refreshInterval: 10 # File/submodule refresh interval in seconds. Auto-refresh can be disabled via option 'git.autoRefresh'.
|
|
||||||
fetchInterval: 60 # Re-fetch interval in seconds. Auto-fetch can be disabled via option 'git.autoFetch'.
|
# This determines whether the git graph is rendered in the commits panel
|
||||||
|
# One of 'always' | 'never' | 'when-maximised'
|
||||||
|
#
|
||||||
|
# Deprecated: Configure this with `Log menu -> Show git graph` (<c-l> in the commits window by default).
|
||||||
|
showGraph: always
|
||||||
|
|
||||||
|
# displays the whole git graph by default in the commits view (equivalent to passing the `--all` argument to `git log`)
|
||||||
|
showWholeGraph: false
|
||||||
|
|
||||||
|
# When copying commit hashes to the clipboard, truncate them to this
|
||||||
|
# length. Set to 40 to disable truncation.
|
||||||
|
truncateCopiedCommitHashesTo: 12
|
||||||
|
|
||||||
|
# Periodic update checks
|
||||||
update:
|
update:
|
||||||
method: prompt # can be: prompt | background | never
|
# One of: 'prompt' (default) | 'background' | 'never'
|
||||||
days: 14 # how often an update is checked for
|
method: prompt
|
||||||
|
|
||||||
|
# Period in days between update checks
|
||||||
|
days: 14
|
||||||
|
|
||||||
|
# Background refreshes
|
||||||
|
refresher:
|
||||||
|
# File/submodule refresh interval in seconds.
|
||||||
|
# Auto-refresh can be disabled via option 'git.autoRefresh'.
|
||||||
|
refreshInterval: 10
|
||||||
|
|
||||||
|
# Re-fetch interval in seconds.
|
||||||
|
# Auto-fetch can be disabled via option 'git.autoFetch'.
|
||||||
|
fetchInterval: 60
|
||||||
|
|
||||||
|
# If true, show a confirmation popup before quitting Lazygit
|
||||||
confirmOnQuit: false
|
confirmOnQuit: false
|
||||||
# determines whether hitting 'esc' will quit the application when there is nothing to cancel/close
|
|
||||||
|
# If true, exit Lazygit when the user presses escape in a context where there is nothing to cancel/close
|
||||||
quitOnTopLevelReturn: false
|
quitOnTopLevelReturn: false
|
||||||
|
|
||||||
|
# Config relating to things outside of Lazygit like how files are opened, copying to clipboard, etc
|
||||||
|
os:
|
||||||
|
# Command for editing a file. Should contain "{{filename}}".
|
||||||
|
edit: ""
|
||||||
|
|
||||||
|
# Command for editing a file at a given line number. Should contain
|
||||||
|
# "{{filename}}", and may optionally contain "{{line}}".
|
||||||
|
editAtLine: ""
|
||||||
|
|
||||||
|
# Same as EditAtLine, except that the command needs to wait until the
|
||||||
|
# window is closed.
|
||||||
|
editAtLineAndWait: ""
|
||||||
|
|
||||||
|
# For opening a directory in an editor
|
||||||
|
openDirInEditor: ""
|
||||||
|
|
||||||
|
# A built-in preset that sets all of the above settings. Supported presets
|
||||||
|
# are defined in the getPreset function in editor_presets.go.
|
||||||
|
editPreset: ""
|
||||||
|
|
||||||
|
# Command for opening a file, as if the file is double-clicked. Should
|
||||||
|
# contain "{{filename}}", but doesn't support "{{line}}".
|
||||||
|
open: ""
|
||||||
|
|
||||||
|
# Command for opening a link. Should contain "{{link}}".
|
||||||
|
openLink: ""
|
||||||
|
|
||||||
|
# EditCommand is the command for editing a file.
|
||||||
|
# Deprecated: use Edit instead. Note that semantics are different:
|
||||||
|
# EditCommand is just the command itself, whereas Edit contains a
|
||||||
|
# "{{filename}}" variable.
|
||||||
|
editCommand: ""
|
||||||
|
|
||||||
|
# EditCommandTemplate is the command template for editing a file
|
||||||
|
# Deprecated: use EditAtLine instead.
|
||||||
|
editCommandTemplate: ""
|
||||||
|
|
||||||
|
# OpenCommand is the command for opening a file
|
||||||
|
# Deprecated: use Open instead.
|
||||||
|
openCommand: ""
|
||||||
|
|
||||||
|
# OpenLinkCommand is the command for opening a link
|
||||||
|
# Deprecated: use OpenLink instead.
|
||||||
|
openLinkCommand: ""
|
||||||
|
|
||||||
|
# CopyToClipboardCmd is the command for copying to clipboard.
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
|
||||||
|
copyToClipboardCmd: ""
|
||||||
|
|
||||||
|
# ReadFromClipboardCmd is the command for reading the clipboard.
|
||||||
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
|
||||||
|
readFromClipboardCmd: ""
|
||||||
|
|
||||||
|
# If true, don't display introductory popups upon opening Lazygit.
|
||||||
disableStartupPopups: false
|
disableStartupPopups: false
|
||||||
notARepository: 'prompt' # one of: 'prompt' | 'create' | 'skip' | 'quit'
|
|
||||||
promptToReturnFromSubprocess: true # display confirmation when subprocess terminates
|
# What to do when opening Lazygit outside of a git repo.
|
||||||
|
# - 'prompt': (default) ask whether to initialize a new repo or open in the most recent repo
|
||||||
|
# - 'create': initialize a new repo
|
||||||
|
# - 'skip': open most recent repo
|
||||||
|
# - 'quit': exit Lazygit
|
||||||
|
notARepository: prompt
|
||||||
|
|
||||||
|
# If true, display a confirmation when subprocess terminates. This allows you to view the output of the subprocess before returning to Lazygit.
|
||||||
|
promptToReturnFromSubprocess: true
|
||||||
|
|
||||||
|
# Keybindings
|
||||||
keybinding:
|
keybinding:
|
||||||
universal:
|
universal:
|
||||||
quit: 'q'
|
quit: q
|
||||||
quit-alt1: '<c-c>' # alternative/alias of quit
|
quit-alt1: <c-c>
|
||||||
return: '<esc>' # return to previous menu, will quit if there's nowhere to return
|
return: <esc>
|
||||||
quitWithoutChangingDirectory: 'Q'
|
quitWithoutChangingDirectory: Q
|
||||||
togglePanel: '<tab>' # goto the next panel
|
togglePanel: <tab>
|
||||||
prevItem: '<up>' # go one line up
|
prevItem: <up>
|
||||||
nextItem: '<down>' # go one line down
|
nextItem: <down>
|
||||||
prevItem-alt: 'k' # go one line up
|
prevItem-alt: k
|
||||||
nextItem-alt: 'j' # go one line down
|
nextItem-alt: j
|
||||||
prevPage: ',' # go to next page in list
|
prevPage: ','
|
||||||
nextPage: '.' # go to previous page in list
|
nextPage: .
|
||||||
gotoTop: '<' # go to top of list
|
scrollLeft: H
|
||||||
gotoBottom: '>' # go to bottom of list
|
scrollRight: L
|
||||||
scrollLeft: 'H' # scroll left within list view
|
gotoTop: <
|
||||||
scrollRight: 'L' # scroll right within list view
|
gotoBottom: '>'
|
||||||
prevBlock: '<left>' # goto the previous block / panel
|
toggleRangeSelect: v
|
||||||
nextBlock: '<right>' # goto the next block / panel
|
rangeSelectDown: <s-down>
|
||||||
prevBlock-alt: 'h' # goto the previous block / panel
|
rangeSelectUp: <s-up>
|
||||||
nextBlock-alt: 'l' # goto the next block / panel
|
prevBlock: <left>
|
||||||
jumpToBlock: ['1', '2', '3', '4', '5'] # goto the Nth block / panel
|
nextBlock: <right>
|
||||||
nextMatch: 'n'
|
prevBlock-alt: h
|
||||||
prevMatch: 'N'
|
nextBlock-alt: l
|
||||||
optionMenu: null # show help menu
|
nextBlock-alt2: <tab>
|
||||||
optionMenu-alt1: '?' # show help menu
|
prevBlock-alt2: <backtab>
|
||||||
select: '<space>'
|
jumpToBlock:
|
||||||
goInto: '<enter>'
|
- "1"
|
||||||
openRecentRepos: '<c-r>'
|
- "2"
|
||||||
confirm: '<enter>'
|
- "3"
|
||||||
remove: 'd'
|
- "4"
|
||||||
new: 'n'
|
- "5"
|
||||||
edit: 'e'
|
nextMatch: "n"
|
||||||
openFile: 'o'
|
prevMatch: "N"
|
||||||
scrollUpMain: '<pgup>' # main panel scroll up
|
startSearch: /
|
||||||
scrollDownMain: '<pgdown>' # main panel scroll down
|
optionMenu: <disabled>
|
||||||
scrollUpMain-alt1: 'K' # main panel scroll up
|
optionMenu-alt1: '?'
|
||||||
scrollDownMain-alt1: 'J' # main panel scroll down
|
select: <space>
|
||||||
scrollUpMain-alt2: '<c-u>' # main panel scroll up
|
goInto: <enter>
|
||||||
scrollDownMain-alt2: '<c-d>' # main panel scroll down
|
confirm: <enter>
|
||||||
|
confirmInEditor: <a-enter>
|
||||||
|
remove: d
|
||||||
|
new: "n"
|
||||||
|
edit: e
|
||||||
|
openFile: o
|
||||||
|
scrollUpMain: <pgup>
|
||||||
|
scrollDownMain: <pgdown>
|
||||||
|
scrollUpMain-alt1: K
|
||||||
|
scrollDownMain-alt1: J
|
||||||
|
scrollUpMain-alt2: <c-u>
|
||||||
|
scrollDownMain-alt2: <c-d>
|
||||||
executeCustomCommand: ':'
|
executeCustomCommand: ':'
|
||||||
createRebaseOptionsMenu: 'm'
|
createRebaseOptionsMenu: m
|
||||||
pushFiles: 'P'
|
|
||||||
pullFiles: 'p'
|
# 'Files' appended for legacy reasons
|
||||||
refresh: 'R'
|
pushFiles: P
|
||||||
createPatchOptionsMenu: '<c-p>'
|
|
||||||
|
# 'Files' appended for legacy reasons
|
||||||
|
pullFiles: p
|
||||||
|
refresh: R
|
||||||
|
createPatchOptionsMenu: <c-p>
|
||||||
nextTab: ']'
|
nextTab: ']'
|
||||||
prevTab: '['
|
prevTab: '['
|
||||||
nextScreenMode: '+'
|
nextScreenMode: +
|
||||||
prevScreenMode: '_'
|
prevScreenMode: _
|
||||||
undo: 'z'
|
undo: z
|
||||||
redo: '<c-z>'
|
redo: <c-z>
|
||||||
filteringMenu: '<c-s>'
|
filteringMenu: <c-s>
|
||||||
diffingMenu: 'W'
|
diffingMenu: W
|
||||||
diffingMenu-alt: '<c-e>' # deprecated
|
diffingMenu-alt: <c-e>
|
||||||
copyToClipboard: '<c-o>'
|
copyToClipboard: <c-o>
|
||||||
submitEditorText: '<enter>'
|
openRecentRepos: <c-r>
|
||||||
|
submitEditorText: <enter>
|
||||||
extrasMenu: '@'
|
extrasMenu: '@'
|
||||||
toggleWhitespaceInDiffView: '<c-w>'
|
toggleWhitespaceInDiffView: <c-w>
|
||||||
increaseContextInDiffView: '}'
|
increaseContextInDiffView: '}'
|
||||||
decreaseContextInDiffView: '{'
|
decreaseContextInDiffView: '{'
|
||||||
|
increaseRenameSimilarityThreshold: )
|
||||||
|
decreaseRenameSimilarityThreshold: (
|
||||||
|
openDiffTool: <c-t>
|
||||||
status:
|
status:
|
||||||
checkForUpdate: 'u'
|
checkForUpdate: u
|
||||||
recentRepos: '<enter>'
|
recentRepos: <enter>
|
||||||
|
allBranchesLogGraph: a
|
||||||
files:
|
files:
|
||||||
commitChanges: 'c'
|
commitChanges: c
|
||||||
commitChangesWithoutHook: 'w' # commit changes without pre-commit hook
|
commitChangesWithoutHook: w
|
||||||
amendLastCommit: 'A'
|
amendLastCommit: A
|
||||||
commitChangesWithEditor: 'C'
|
commitChangesWithEditor: C
|
||||||
ignoreFile: 'i'
|
findBaseCommitForFixup: <c-f>
|
||||||
refreshFiles: 'r'
|
confirmDiscard: x
|
||||||
stashAllChanges: 's'
|
ignoreFile: i
|
||||||
viewStashOptions: 'S'
|
refreshFiles: r
|
||||||
toggleStagedAll: 'a' # stage/unstage all
|
stashAllChanges: s
|
||||||
viewResetOptions: 'D'
|
viewStashOptions: S
|
||||||
fetch: 'f'
|
toggleStagedAll: a
|
||||||
|
viewResetOptions: D
|
||||||
|
fetch: f
|
||||||
toggleTreeView: '`'
|
toggleTreeView: '`'
|
||||||
openMergeTool: 'M'
|
openMergeTool: M
|
||||||
openStatusFilter: '<c-b>'
|
openStatusFilter: <c-b>
|
||||||
|
copyFileInfoToClipboard: "y"
|
||||||
branches:
|
branches:
|
||||||
createPullRequest: 'o'
|
createPullRequest: o
|
||||||
viewPullRequestOptions: 'O'
|
viewPullRequestOptions: O
|
||||||
checkoutBranchByName: 'c'
|
copyPullRequestURL: <c-y>
|
||||||
forceCheckoutBranch: 'F'
|
checkoutBranchByName: c
|
||||||
rebaseBranch: 'r'
|
forceCheckoutBranch: F
|
||||||
renameBranch: 'R'
|
rebaseBranch: r
|
||||||
mergeIntoCurrentBranch: 'M'
|
renameBranch: R
|
||||||
viewGitFlowOptions: 'i'
|
mergeIntoCurrentBranch: M
|
||||||
fastForward: 'f' # fast-forward this branch from its upstream
|
viewGitFlowOptions: i
|
||||||
createTag: 'T'
|
fastForward: f
|
||||||
pushTag: 'P'
|
createTag: T
|
||||||
setUpstream: 'u' # set as upstream of checked-out branch
|
pushTag: P
|
||||||
fetchRemote: 'f'
|
setUpstream: u
|
||||||
|
fetchRemote: f
|
||||||
|
sortOrder: s
|
||||||
|
worktrees:
|
||||||
|
viewWorktreeOptions: w
|
||||||
commits:
|
commits:
|
||||||
squashDown: 's'
|
squashDown: s
|
||||||
renameCommit: 'r'
|
renameCommit: r
|
||||||
renameCommitWithEditor: 'R'
|
renameCommitWithEditor: R
|
||||||
viewResetOptions: 'g'
|
viewResetOptions: g
|
||||||
markCommitAsFixup: 'f'
|
markCommitAsFixup: f
|
||||||
createFixupCommit: 'F' # create fixup commit for this commit
|
createFixupCommit: F
|
||||||
squashAboveCommits: 'S'
|
squashAboveCommits: S
|
||||||
moveDownCommit: '<c-j>' # move commit down one
|
moveDownCommit: <c-j>
|
||||||
moveUpCommit: '<c-k>' # move commit up one
|
moveUpCommit: <c-k>
|
||||||
amendToCommit: 'A'
|
amendToCommit: A
|
||||||
pickCommit: 'p' # pick commit (when mid-rebase)
|
resetCommitAuthor: a
|
||||||
revertCommit: 't'
|
pickCommit: p
|
||||||
cherryPickCopy: 'c'
|
revertCommit: t
|
||||||
cherryPickCopyRange: 'C'
|
cherryPickCopy: C
|
||||||
pasteCommits: 'v'
|
pasteCommits: V
|
||||||
tagCommit: 'T'
|
markCommitAsBaseForRebase: B
|
||||||
checkoutCommit: '<space>'
|
tagCommit: T
|
||||||
resetCherryPick: '<c-R>'
|
checkoutCommit: <space>
|
||||||
copyCommitMessageToClipboard: '<c-y>'
|
resetCherryPick: <c-R>
|
||||||
openLogMenu: '<c-l>'
|
copyCommitAttributeToClipboard: "y"
|
||||||
viewBisectOptions: 'b'
|
openLogMenu: <c-l>
|
||||||
|
openInBrowser: o
|
||||||
|
viewBisectOptions: b
|
||||||
|
startInteractiveRebase: i
|
||||||
|
amendAttribute:
|
||||||
|
resetAuthor: a
|
||||||
|
setAuthor: A
|
||||||
|
addCoAuthor: c
|
||||||
stash:
|
stash:
|
||||||
popStash: 'g'
|
popStash: g
|
||||||
renameStash: 'r'
|
renameStash: r
|
||||||
commitFiles:
|
commitFiles:
|
||||||
checkoutCommitFile: 'c'
|
checkoutCommitFile: c
|
||||||
main:
|
main:
|
||||||
toggleDragSelect: 'v'
|
toggleSelectHunk: a
|
||||||
toggleDragSelect-alt: 'V'
|
pickBothHunks: b
|
||||||
toggleSelectHunk: 'a'
|
editSelectHunk: E
|
||||||
pickBothHunks: 'b'
|
|
||||||
submodules:
|
submodules:
|
||||||
init: 'i'
|
init: i
|
||||||
update: 'u'
|
update: u
|
||||||
bulkMenu: 'b'
|
bulkMenu: b
|
||||||
|
commitMessage:
|
||||||
|
commitMenu: <c-o>
|
||||||
```
|
```
|
||||||
|
<!-- END CONFIG YAML -->
|
||||||
|
|
||||||
## Platform Defaults
|
## Platform Defaults
|
||||||
|
|
||||||
@@ -279,29 +634,42 @@ os:
|
|||||||
open: 'open {{filename}}'
|
open: 'open {{filename}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuring File Editing
|
## Custom Command for Copying to and Pasting from Clipboard
|
||||||
|
```yaml
|
||||||
|
os:
|
||||||
|
copyToClipboardCmd: ''
|
||||||
|
```
|
||||||
|
Specify an external command to invoke when copying to clipboard is requested. `{{text}` will be replaced by text to be copied. Default is to copy to system clipboard.
|
||||||
|
|
||||||
There are two commands for opening files, `o` for "open" and `e` for "edit". `o`
|
If you are working on a terminal that supports OSC52, the following command will let you take advantage of it:
|
||||||
acts as if the file was double-clicked in the Finder/Explorer, so it also works
|
```
|
||||||
for non-text files, whereas `e` opens the file in an editor. `e` can also jump
|
os:
|
||||||
to the right line in the file if you invoke it from the staging panel, for
|
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64)\a" > /dev/tty
|
||||||
example.
|
```
|
||||||
|
|
||||||
To tell lazygit which editor to use for the `e` command, the easiest way to do
|
A custom command for reading from the clipboard can be set using
|
||||||
that is to provide an editPreset config, e.g.
|
```yaml
|
||||||
|
os:
|
||||||
|
readFromClipboardCmd: ''
|
||||||
|
```
|
||||||
|
It is used, for example, when pasting a commit message into the commit message panel. The command is supposed to output the clipboard content to stdout.
|
||||||
|
|
||||||
|
## Configuring File Editing
|
||||||
|
|
||||||
|
There are two commands for opening files, `o` for "open" and `e` for "edit". `o` acts as if the file was double-clicked in the Finder/Explorer, so it also works for non-text files, whereas `e` opens the file in an editor. `e` can also jump to the right line in the file if you invoke it from the staging panel, for example.
|
||||||
|
|
||||||
|
To tell lazygit which editor to use for the `e` command, the easiest way to do that is to provide an editPreset config, e.g.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
os:
|
os:
|
||||||
editPreset: 'vscode'
|
editPreset: 'vscode'
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported presets are `vim`, `nvim`, `emacs`, `nano`, `vscode`, `sublime`, `bbedit`,
|
Supported presets are `vim`, `nvim`, `nvim-remote`, `lvim`, `emacs`, `nano`, `micro`, `vscode`, `sublime`, `bbedit`, `kakoune`, `helix`, and `xcode`. In many cases lazygit will be able to guess the right preset from your $(git config core.editor), or an environment variable such as $VISUAL or $EDITOR.
|
||||||
`kakoune`, `helix`, and `xcode`. In many cases lazygit will be able to guess the right preset
|
|
||||||
from your $(git config core.editor), or an environment variable such as $VISUAL or $EDITOR.
|
|
||||||
|
|
||||||
If for some reason you are not happy with the default commands from a preset, or
|
`nvim-remote` is an experimental preset for when you have invoked lazygit from within a neovim process, allowing lazygit to open the file from within the parent process rather than spawning a new one.
|
||||||
there simply is no preset for your editor, you can customize the commands by
|
|
||||||
setting the `edit`, `editAtLine`, and `editAtLineAndWait` options, e.g.:
|
If for some reason you are not happy with the default commands from a preset, or there simply is no preset for your editor, you can customize the commands by setting the `edit`, `editAtLine`, and `editAtLineAndWait` options, e.g.:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
os:
|
os:
|
||||||
@@ -309,15 +677,14 @@ os:
|
|||||||
editAtLine: 'myeditor --line={{line}} {{filename}}'
|
editAtLine: 'myeditor --line={{line}} {{filename}}'
|
||||||
editAtLineAndWait: 'myeditor --block --line={{line}} {{filename}}'
|
editAtLineAndWait: 'myeditor --block --line={{line}} {{filename}}'
|
||||||
editInTerminal: true
|
editInTerminal: true
|
||||||
|
openDirInEditor: 'myeditor {{dir}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
The `editInTerminal` option is used to decide whether lazygit needs to suspend
|
The `editInTerminal` option is used to decide whether lazygit needs to suspend itself to the background before calling the editor. It should really be named `suspend` because for some cases like when lazygit is opened from within a neovim session and you're using the `nvim-remote` preset, you're technically still in a terminal. Nonetheless we're sticking with the name `editInTerminal` for backwards compatibility.
|
||||||
itself to the background before calling the editor.
|
|
||||||
|
|
||||||
Contributions of new editor presets are welcome; see the `getPreset` function in
|
Contributions of new editor presets are welcome; see the `getPreset` function in [`editor_presets.go`](https://github.com/jesseduffield/lazygit/blob/master/pkg/config/editor_presets.go).
|
||||||
[`editor_presets.go`](https://github.com/jesseduffield/lazygit/blob/master/pkg/config/editor_presets.go).
|
|
||||||
|
|
||||||
### Overriding default config file location
|
## Overriding default config file location
|
||||||
|
|
||||||
To override the default config directory, use `CONFIG_DIR="$HOME/.config/lazygit"`. This directory contains the config file in addition to some other files lazygit uses to keep track of state across sessions.
|
To override the default config directory, use `CONFIG_DIR="$HOME/.config/lazygit"`. This directory contains the config file in addition to some other files lazygit uses to keep track of state across sessions.
|
||||||
|
|
||||||
@@ -331,6 +698,20 @@ or
|
|||||||
LG_CONFIG_FILE="$HOME/.base_lg_conf,$HOME/.light_theme_lg_conf" lazygit
|
LG_CONFIG_FILE="$HOME/.base_lg_conf,$HOME/.light_theme_lg_conf" lazygit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Scroll-off Margin
|
||||||
|
|
||||||
|
When the selected line gets close to the bottom of the window and you hit down-arrow, there's a feature called "scroll-off margin" that lets the view scroll a little earlier so that you can see a bit of what's coming in the direction that you are moving. This is controlled by the `gui.scrollOffMargin` setting (default: 2), so it keeps 2 lines below the selection visible as you scroll down. It can be set to 0 to scroll only when the selection reaches the bottom of the window.
|
||||||
|
|
||||||
|
That's the behavior when `gui.scrollOffBehavior` is set to "margin" (the default). If you set `gui.scrollOffBehavior` to "jump", then upon reaching the last line of a view and hitting down-arrow the view will scroll by half a page so that the selection ends up in the middle of the view. This may feel a little jarring because the cursor jumps around when continuously moving down, but it has the advantage that the view doesn't scroll as often.
|
||||||
|
|
||||||
|
This setting applies both to all list views (e.g. commits and branches etc), and to the staging view.
|
||||||
|
|
||||||
|
## Filtering
|
||||||
|
|
||||||
|
We have two ways to filter things, substring matching (the default) and fuzzy searching. With substring matching, the text you enter gets searched for verbatim (usually case-insensitive, except when your filter string contains uppercase letters, in which case we search case-sensitively). You can search for multiple non-contiguous substrings by separating them with spaces; for example, "int test" will match "integration-testing". All substrings have to match, but not necessarily in the given order.
|
||||||
|
|
||||||
|
Fuzzy searching is smarter in that it allows every letter of the filter string to match anywhere in the text (only in order though), assigning a weight to the quality of the match and sorting by that order. This has the advantage that it allows typing "clt" to match "commit_loader_test" (letters at the beginning of subwords get more weight); but it has the disadvantage that it tends to return lots of irrelevant results, especially with short filter strings.
|
||||||
|
|
||||||
## Color Attributes
|
## Color Attributes
|
||||||
|
|
||||||
For color attributes you can choose an array of attributes (with max one color attribute)
|
For color attributes you can choose an array of attributes (with max one color attribute)
|
||||||
@@ -358,15 +739,13 @@ The available attributes are:
|
|||||||
|
|
||||||
## Highlighting the selected line
|
## Highlighting the selected line
|
||||||
|
|
||||||
If you don't like the default behaviour of highlighting the selected line with a blue background, you can use the `selectedLineBgColor` and `selectedRangeBgColor` keys to customise the behaviour. If you just want to embolden the selected line (this was the original default), you can do the following:
|
If you don't like the default behaviour of highlighting the selected line with a blue background, you can use the `selectedLineBgColor` key to customise the behaviour. If you just want to embolden the selected line (this was the original default), you can do the following:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
gui:
|
gui:
|
||||||
theme:
|
theme:
|
||||||
selectedLineBgColor:
|
selectedLineBgColor:
|
||||||
- default
|
- default
|
||||||
selectedRangeBgColor:
|
|
||||||
- default
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the reverse attribute like so:
|
You can also use the reverse attribute like so:
|
||||||
@@ -376,8 +755,6 @@ gui:
|
|||||||
theme:
|
theme:
|
||||||
selectedLineBgColor:
|
selectedLineBgColor:
|
||||||
- reverse
|
- reverse
|
||||||
selectedRangeBgColor:
|
|
||||||
- reverse
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom Author Color
|
## Custom Author Color
|
||||||
@@ -427,19 +804,18 @@ gui:
|
|||||||
nerdFontsVersion: "3"
|
nerdFontsVersion: "3"
|
||||||
```
|
```
|
||||||
|
|
||||||
Supported versions are "2" and "3". The deprecated config `showIcons` sets the
|
Supported versions are "2" and "3". The deprecated config `showIcons` sets the version to "2" for backwards compatibility.
|
||||||
version to "2" for backwards compatibility.
|
|
||||||
|
|
||||||
## Keybindings
|
## Keybindings
|
||||||
|
|
||||||
For all possible keybinding options, check [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md)
|
For all possible keybinding options, check [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md)
|
||||||
|
|
||||||
You can disable certain key bindings by specifying `null`.
|
You can disable certain key bindings by specifying `<disabled>`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
keybinding:
|
keybinding:
|
||||||
universal:
|
universal:
|
||||||
edit: null # disable 'edit file'
|
edit: <disabled> # disable 'edit file'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example Keybindings For Colemak Users
|
### Example Keybindings For Colemak Users
|
||||||
@@ -476,9 +852,7 @@ keybinding:
|
|||||||
|
|
||||||
## Custom pull request URLs
|
## Custom pull request URLs
|
||||||
|
|
||||||
Some git provider setups (e.g. on-premises GitLab) can have distinct URLs for git-related calls and
|
Some git provider setups (e.g. on-premises GitLab) can have distinct URLs for git-related calls and the web interface/API itself. To work with those, Lazygit needs to know where it needs to create the pull request. You can do so on your `config.yml` file using the following syntax:
|
||||||
the web interface/API itself. To work with those, Lazygit needs to know where it needs to create
|
|
||||||
the pull request. You can do so on your `config.yml` file using the following syntax:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
@@ -493,14 +867,22 @@ Where:
|
|||||||
|
|
||||||
## Predefined commit message prefix
|
## Predefined commit message prefix
|
||||||
|
|
||||||
In situations where certain naming pattern is used for branches and commits, pattern can be used to populate
|
In situations where certain naming pattern is used for branches and commits, pattern can be used to populate commit message with prefix that is parsed from the branch name.
|
||||||
commit message with prefix that is parsed from the branch name.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
- Branch name: feature/AB-123
|
- Branch name: feature/AB-123
|
||||||
- Commit message: [AB-123] Adding feature
|
- Commit message: [AB-123] Adding feature
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
commitPrefix:
|
||||||
|
pattern: "^\\w+\\/(\\w+-\\w+).*"
|
||||||
|
replace: '[$1] '
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both `commitPrefixes` defined and an entry in `commitPrefixes` for the current repo, the `commitPrefixes` entry is given higher precedence. Repository folder names must be an exact match.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
git:
|
git:
|
||||||
commitPrefixes:
|
commitPrefixes:
|
||||||
@@ -509,6 +891,21 @@ git:
|
|||||||
replace: '[$1] '
|
replace: '[$1] '
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Predefined branch name prefix
|
||||||
|
|
||||||
|
In situations where certain naming pattern is used for branches, this can be used to populate new branch creation with a static prefix.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
Some branches:
|
||||||
|
- jsmith/AB-123
|
||||||
|
- cwilson/AB-125
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
branchPrefix: "firstlast/"
|
||||||
|
```
|
||||||
|
|
||||||
## Custom git log command
|
## Custom git log command
|
||||||
|
|
||||||
You can override the `git log` command that's used to render the log of the selected branch like so:
|
You can override the `git log` command that's used to render the log of the selected branch like so:
|
||||||
@@ -524,9 +921,7 @@ Result:
|
|||||||
|
|
||||||
## Launching not in a repository behaviour
|
## Launching not in a repository behaviour
|
||||||
|
|
||||||
By default, when launching lazygit from a directory that is not a repository,
|
By default, when launching lazygit from a directory that is not a repository, you will be prompted to choose if you would like to initialize a repo. You can override this behaviour in the config with one of the following:
|
||||||
you will be prompted to choose if you would like to initialize a repo. You can
|
|
||||||
override this behaviour in the config with one of the following:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# for default prompting behaviour
|
# for default prompting behaviour
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ You can add custom command keybindings in your config.yml (accessible by pressin
|
|||||||
customCommands:
|
customCommands:
|
||||||
- key: '<c-r>'
|
- key: '<c-r>'
|
||||||
context: 'commits'
|
context: 'commits'
|
||||||
command: 'hub browse -- "commit/{{.SelectedLocalCommit.Sha}}"'
|
command: 'hub browse -- "commit/{{.SelectedLocalCommit.Hash}}"'
|
||||||
- key: 'a'
|
- key: 'a'
|
||||||
context: 'files'
|
context: 'files'
|
||||||
command: "git {{if .SelectedFile.HasUnstagedChanges}} add {{else}} reset {{end}} {{.SelectedFile.Name | quote}}"
|
command: "git {{if .SelectedFile.HasUnstagedChanges}} add {{else}} reset {{end}} {{.SelectedFile.Name | quote}}"
|
||||||
@@ -59,6 +59,13 @@ For a given custom command, here are the allowed fields:
|
|||||||
| description | Label for the custom command when displayed in the keybindings menu | no |
|
| description | Label for the custom command when displayed in the keybindings menu | no |
|
||||||
| stream | Whether you want to stream the command's output to the Command Log panel | no |
|
| stream | Whether you want to stream the command's output to the Command Log panel | no |
|
||||||
| showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
|
| showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
|
||||||
|
| outputTitle | The title to display in the popup panel if showOutput is true. If left unset, the command will be used as the title. | no |
|
||||||
|
| after | Actions to take after the command has completed | no |
|
||||||
|
|
||||||
|
Here are the options for the `after` key:
|
||||||
|
| _field_ | _description_ | required |
|
||||||
|
|-----------------|----------------------|-|
|
||||||
|
| checkForConflicts | true/false. If true, check for merge conflicts | no |
|
||||||
|
|
||||||
## Contexts
|
## Contexts
|
||||||
|
|
||||||
@@ -68,6 +75,7 @@ The permitted contexts are:
|
|||||||
| -------------- | -------------------------------------------------------------------------------------------------------- |
|
| -------------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
| status | The 'Status' tab |
|
| status | The 'Status' tab |
|
||||||
| files | The 'Files' tab |
|
| files | The 'Files' tab |
|
||||||
|
| worktrees | The 'Worktrees' tab |
|
||||||
| localBranches | The 'Local Branches' tab |
|
| localBranches | The 'Local Branches' tab |
|
||||||
| remotes | The 'Remotes' tab |
|
| remotes | The 'Remotes' tab |
|
||||||
| remoteBranches | The context you get when pressing enter on a remote in the remotes tab |
|
| remoteBranches | The context you get when pressing enter on a remote in the remotes tab |
|
||||||
@@ -294,10 +302,11 @@ SelectedRemote
|
|||||||
SelectedTag
|
SelectedTag
|
||||||
SelectedStashEntry
|
SelectedStashEntry
|
||||||
SelectedCommitFile
|
SelectedCommitFile
|
||||||
|
SelectedWorktree
|
||||||
CheckedOutBranch
|
CheckedOutBranch
|
||||||
```
|
```
|
||||||
|
|
||||||
To see what fields are available on e.g. the `SelectedFile`, see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/commands/models/file.go) (all the modelling lives in the same directory). Note that the custom commands feature does not guarantee backwards compatibility (until we hit Lazygit version 1.0 of course) which means a field you're accessing on an object may no longer be available from one release to the next. Typically however, all you'll need is `{{.SelectedFile.Name}}`, `{{.SelectedLocalCommit.Sha}}` and `{{.SelectedLocalBranch.Name}}`. In the future we will likely introduce a tighter interface that exposes a limited set of fields for each model.
|
To see what fields are available on e.g. the `SelectedFile`, see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/gui/services/custom_commands/models.go) (all the modelling lives in the same file).
|
||||||
|
|
||||||
## Keybinding collisions
|
## Keybinding collisions
|
||||||
|
|
||||||
|
|||||||
+23
-1
@@ -1,6 +1,6 @@
|
|||||||
# Custom Pagers
|
# Custom Pagers
|
||||||
|
|
||||||
Lazygit supports custom pagers, [configured](/docs/Config.md) in the config.yml file (which can be opened by pressing `o` in the Status panel).
|
Lazygit supports custom pagers, [configured](/docs/Config.md) in the config.yml file (which can be opened by pressing `e` in the Status panel).
|
||||||
|
|
||||||
Support does not extend to Windows users, because we're making use of a package which doesn't have Windows support.
|
Support does not extend to Windows users, because we're making use of a package which doesn't have Windows support.
|
||||||
|
|
||||||
@@ -62,3 +62,25 @@ git:
|
|||||||
```
|
```
|
||||||
|
|
||||||
If you set `useConfig: true`, lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
|
If you set `useConfig: true`, lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
|
||||||
|
|
||||||
|
## Using external diff commands
|
||||||
|
|
||||||
|
Some diff tools can't work as a simple pager like the ones above do, because they need access to the entire diff, so just post-processing git's diff is not enough for them. The most notable example is probably [difftastic](https://difftastic.wilfred.me.uk).
|
||||||
|
|
||||||
|
These can be used in lazygit by using the `externalDiffCommand` config; in the case of difftastic, that could be
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
paging:
|
||||||
|
externalDiffCommand: difft --color=always
|
||||||
|
```
|
||||||
|
|
||||||
|
The `colorArg`, `pager`, and `useConfig` options are not used in this case.
|
||||||
|
|
||||||
|
You can add whatever extra arguments you prefer for your difftool; for instance
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
paging:
|
||||||
|
externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Fixup Commits
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
There's this common scenario that you have a PR in review, the reviewer is
|
||||||
|
requesting some changes, and you make those changes and would normally simply
|
||||||
|
squash them into the original commit that they came from. If you do that,
|
||||||
|
however, there's no way for the reviewer to see what you changed. You could just
|
||||||
|
make a separate commit with those changes at the end of the branch, but this is
|
||||||
|
not ideal because it results in a git history that is not very clean.
|
||||||
|
|
||||||
|
To help with this, git has a concept of fixup commits: you do make a separate
|
||||||
|
commit, but the subject of this commit is the string "fixup! " followed by the
|
||||||
|
original commit subject. This both tells the reviewer what's going on (you are
|
||||||
|
making a change that you later will squash into the designated commit), and it
|
||||||
|
provides an easy way to actually perform this squash operation when you are
|
||||||
|
ready to do that (before merging).
|
||||||
|
|
||||||
|
## Creating fixup commits
|
||||||
|
|
||||||
|
You could of course create fixup commits manually by typing in the commit
|
||||||
|
message with the prefix yourself. But lazygit has an easier way to do that:
|
||||||
|
in the Commits view, select the commit that you want to create a fixup for, and
|
||||||
|
press shift-F (for "Create fixup commit for this commit"). This automatically
|
||||||
|
creates a commit with the appropriate subject line.
|
||||||
|
|
||||||
|
Don't confuse this with the lowercase "f" command ("Fixup commit"); that one
|
||||||
|
squashes the selected commit into its parent, this is not what we want here.
|
||||||
|
|
||||||
|
## Creating amend commits
|
||||||
|
|
||||||
|
There's a special type of fixup commit that uses "amend!" instead of "fixup!" in
|
||||||
|
the commit message subject; in addition to fixing up the original commit with
|
||||||
|
changes it allows you to also (or only) change the commit message of the
|
||||||
|
original commit. The menu that appears when pressing shift-F has options for
|
||||||
|
both of these; they bring up a commit message panel similar to when you reword a
|
||||||
|
commit, but then create the "amend!" commit containing the new message. Note
|
||||||
|
that in that panel you only type the new message as you want it to be
|
||||||
|
eventually; lazygit then takes care of formatting the "amend!" commit
|
||||||
|
appropriately for you (with the subject of your new message moving into the body
|
||||||
|
of the "amend!" commit).
|
||||||
|
|
||||||
|
## Squashing fixup commits
|
||||||
|
|
||||||
|
When you're ready to merge the branch and want to squash all these fixup commits
|
||||||
|
that you created, that's very easy to do: select the first commit of your branch
|
||||||
|
and hit shift-S (for "Squash all 'fixup!' commits above selected commit
|
||||||
|
(autosquash)"). Boom, done.
|
||||||
|
|
||||||
|
## Finding the commit to create a fixup for
|
||||||
|
|
||||||
|
When you are making changes to code that you changed earlier in a long branch,
|
||||||
|
it can be tedious to find the commit to squash it into. Lazygit has a command to
|
||||||
|
help you with this, too: in the Files view, press ctrl-f to select the right
|
||||||
|
base commit in the Commits view automatically. From there, you can either press
|
||||||
|
shift-F to create a fixup commit for it, or shift-A to amend your changes into
|
||||||
|
the commit if you haven't published your branch yet.
|
||||||
|
|
||||||
|
If you have many modifications in your working copy, it is a good idea to stage
|
||||||
|
related changes that are meant to go into the same fixup commit; if no changes
|
||||||
|
are staged, ctrl-f works on all unstaged modifications, and then it might show
|
||||||
|
an error if it finds multiple different base commits. If you are interested in
|
||||||
|
what the command does to do its magic, and how you can help it work better, you
|
||||||
|
may want to read the [design document](dev/Find_Base_Commit_For_Fixup_Design.md)
|
||||||
|
that describes this.
|
||||||
+11
-9
@@ -1,9 +1,11 @@
|
|||||||
# Documentation Overview
|
# Documentation Overview
|
||||||
|
|
||||||
* [Configuration](./Config.md).
|
* [Configuration](./Config.md).
|
||||||
* [Custom Commands](./Custom_Command_Keybindings.md)
|
* [Custom Commands](./Custom_Command_Keybindings.md)
|
||||||
* [Custom Pagers](./Custom_Pagers.md)
|
* [Custom Pagers](./Custom_Pagers.md)
|
||||||
* [Keybindings](./keybindings)
|
* [Dev docs](./dev)
|
||||||
* [Undo/Redo](./Undoing.md)
|
* [Keybindings](./keybindings)
|
||||||
* [Searching/Filtering](./Searching.md)
|
* [Undo/Redo](./Undoing.md)
|
||||||
* [Dev docs](./dev)
|
* [Range Select](./Range_Select.md)
|
||||||
|
* [Searching/Filtering](./Searching.md)
|
||||||
|
* [Stacked Branches](./Stacked_Branches.md)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Range Select
|
||||||
|
|
||||||
|
Some actions can be performed on a range of contiguous items. For example:
|
||||||
|
* staging multiple files at once
|
||||||
|
* squashing multiple commits at once
|
||||||
|
* copying (for cherry-pick) multiple commits at once
|
||||||
|
|
||||||
|
There are two ways to select a range of items:
|
||||||
|
1. Sticky range select: Press 'v' to toggle range select, then expand the selection using the up/down arrow key. To reset the selection, press 'v' again.
|
||||||
|
2. Non-sticky range select: Press shift+up or shift+down to expand the selection. To reset the selection, press up/down without shift.
|
||||||
|
|
||||||
|
The sticky option will be more familiar to vim users, and the second option will feel more natural to users who aren't used to doing things in a modal way.
|
||||||
|
|
||||||
|
In order to perform an action on a range of items, simply press the normal key for that action. If the action only works on individual items, it will raise an error. This is a new feature and the plan is to incrementally support range select for more and more actions. If there is an action you would like to support range select which currently does not, please raise an issue in the repo.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Working with stacked branches
|
||||||
|
|
||||||
|
When working on a large branch it can often be useful to break it down into
|
||||||
|
smaller pieces, and it can help to create separate branches for each independent
|
||||||
|
chunk of changes. For example, you could have one branch for preparatory
|
||||||
|
refactorings, one for backend changes, and one for frontend changes. Those
|
||||||
|
branches would then all be stacked onto each other.
|
||||||
|
|
||||||
|
Git has support for rebasing such a stack as a whole; you can enable it by
|
||||||
|
setting the git config `rebase.updateRefs` to true. If you then rebase the
|
||||||
|
topmost branch of the stack, the other ones in the stack will follow. This
|
||||||
|
includes interactive rebases, so for example amending a commit in the first
|
||||||
|
branch of the stack will "just work" in the sense that it keeps the other
|
||||||
|
branches properly stacked onto it.
|
||||||
|
|
||||||
|
Lazygit visualizes the individual branch heads in the stack by marking them with a
|
||||||
|
cyan asterisk (or a cyan branch symbol if you are using [nerd
|
||||||
|
fonts](Config.md#display-nerd-fonts-icons)).
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
# Undo/Redo in lazygit
|
# Undo/Redo in lazygit
|
||||||
|
|
||||||

|
You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions.
|
||||||
|
Undo uses the reflog which is specific to commits and branches so we can't undo changes to the working tree or stash.
|
||||||
|
|
||||||
## Keybindings:
|

|
||||||
'z' to undo, 'ctrl+z' to redo
|
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ go utils.Safe(f)
|
|||||||
|
|
||||||
Where `utils.Safe` is a helper function that ensures we clean up the gui if the goroutine panics.
|
Where `utils.Safe` is a helper function that ensures we clean up the gui if the goroutine panics.
|
||||||
|
|
||||||
### Programmatically enqueing a UI event
|
### Programmatically enqueueing a UI event
|
||||||
|
|
||||||
This is invoked with `self.c.OnUIThread(f)`. Internally, it creates a task before enqueuing the function as an event (including the task in the event struct) and once that event is processed by the event queue (and any other pending events are processed) the task is removed from the map by calling `task.Done()`.
|
This is invoked with `self.c.OnUIThread(f)`. Internally, it creates a task before enqueuing the function as an event (including the task in the event struct) and once that event is processed by the event queue (and any other pending events are processed) the task is removed from the map by calling `task.Done()`.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# Lazygit Codebase Guide
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
* `pkg/app`: Contains startup code, inititalises a bunch of stuff like logging, the user config, etc, before starting the gui. Catches and handles some errors that the gui raises.
|
||||||
|
* `pkg/app/daemon`: Contains code relating to the lazygit daemon. This could be better named: it's is not a daemon in the sense that it's a long-running background process; rather it's a short-lived background process that we pass to git for certain tasks, like GIT_EDITOR for when we want to set the TODO file for an interactive rebase.
|
||||||
|
* `pkg/cheatsheet`: Generates the keybinding cheatsheets in `docs/keybindings`.
|
||||||
|
* `pkg/commands/git_commands`: All communication to the git binary happens here. So for example there's a `Checkout` method which calls `git checkout`.
|
||||||
|
* `pkg/commands/oscommands`: Contains code for talking to the OS, and for invoking commands in general
|
||||||
|
* `pkg/commands/git_config`: Reading of the git config all happens here.
|
||||||
|
* `pkg/commands/hosting_service`: Contains code that is specific to git hosting services (aka forges).
|
||||||
|
* `pkg/commands/models`: Contains model structs that represent commits, branches, files, etc.
|
||||||
|
* `pkg/commands/patch`: Contains code for parsing and working with git patches
|
||||||
|
* `pkg/common`: Contains the `Common` struct which holds common dependencies like the logger, i18n, and the user config. Most structs in the code will have a field named `c` which holds a common struct (or a derivative of the common struct).
|
||||||
|
* `pkg/config`: Contains code relating to the Lazygit user config. Specifically `pkg/config/user_config/go` defines the user config struct and its default values.
|
||||||
|
* `pkg/constants`: Contains some constant strings (e.g. links to docs)
|
||||||
|
* `pkg/env`: Contains code relating to setting/getting environment variables
|
||||||
|
* `pkg/i18n`: Contains internationalised strings
|
||||||
|
* `pkg/integration`: Contains end-to-end tests
|
||||||
|
* `pkg/jsonschema`: Contains generator for user config JSON schema.
|
||||||
|
* `pkg/logs`: Contains code for instantiating the logger and for tailing the logs via `lazygit --logs`
|
||||||
|
* `pkg/tasks`: Contains code for running asynchronous tasks: mostly related to efficiently rendering command output to the main window.
|
||||||
|
* `pkg/theme`: Contains code related to colour themes.
|
||||||
|
* `pkg/updates`: Contains code related to Lazygit updates (checking for update, download and installing the update)
|
||||||
|
* `pkg/utils`: Contains lots of low-level helper functions
|
||||||
|
* `pkg/gui`: Contains code related to the gui. We've still got a God Struct in the form of our Gui struct, but over time code has been moved out into contexts, controllers, and helpers, and we intend to continue moving more code out over time.
|
||||||
|
* `pkg/gui/context`: Contains code relating to contexts. There is a context for each view e.g. a branches context, a tags context, etc. Contexts manage state related to the view and receive keypresses.
|
||||||
|
* `pkg/gui/controllers`: Contains code relating to controllers. Controllers define a list of keybindings and their associated handlers. One controller can be assigned to multiple contexts, and one context can contain multiple controllers.
|
||||||
|
* `pkg/gui/controllers/helpers`: Contains code that is shared between multiple controllers.
|
||||||
|
* `pkg/gui/filetree`: Contains code relating to the representation of filetrees.
|
||||||
|
* `pkg/gui/keybindings`: Contains code for mapping between keybindings and their labels
|
||||||
|
* `pkg/gui/mergeconflicts`: Contains code relating to the handling of merge conflicts
|
||||||
|
* `pkg/gui/modes`: Contains code relating to the state of different modes e.g. cherry picking mode, rebase mode.
|
||||||
|
* `pkg/gui/patch_exploring`: Contains code relating to the state of patch-oriented views like the staging view.
|
||||||
|
* `pkg/gui/popup`: Contains code that lets you easily raise popups
|
||||||
|
* `pkg/gui/presentation`: Contains presentation code i.e. code concerned with rendering content inside views
|
||||||
|
* `pkg/gui/services/custom_commands`: Contains code related to user-defined custom commands.
|
||||||
|
* `pkg/gui/status`: Contains code for invoking loaders and toasts
|
||||||
|
* `pkg/gui/style`: Contains code for specifying text styles (colour, bold, etc)
|
||||||
|
* `pkg/gui/types`: Contains various gui-specific types and interfaces. Lots of code lives here to avoid circular dependencies
|
||||||
|
* `vendor/github.com/jesseduffield/gocui`: Gocui is the underlying library used for handling the gui event loop, handling keypresses, and rendering the UI. It defines the View struct which our own context structs build upon.
|
||||||
|
|
||||||
|
## Important files
|
||||||
|
|
||||||
|
* `pkg/config/user_config.go`: defines the user config and default values
|
||||||
|
* `pkg/gui/keybindings.go`: defines keybindings which have not yet been moved into a controller (originally all keybindings were defined here)
|
||||||
|
* `pkg/gui/controllers.go`: links up controllers with contexts
|
||||||
|
* `pkg/gui/controllers/helpers/helpers.go`: defines all the different helper structs
|
||||||
|
* `pkg/commands/git.go`: defines all the different git command structs
|
||||||
|
* `pkg/gui/gui.go`: defines the top-level gui state and gui initialisation/run code
|
||||||
|
* `pkg/gui/layout.go`: defines what happens on each render
|
||||||
|
* `pkg/gui/controllers/helpers/window_arrangement_helper.go`: defines the layout of the UI and the size/position of each window
|
||||||
|
* `pkg/gui/context/context.go`: defines the different contexts
|
||||||
|
* `pkg/gui/context/setup.go`: defines initialisation code for all contexts
|
||||||
|
* `pkg/gui/context.go`: manages the lifecycle of contexts, the context stack, and focus changes.
|
||||||
|
* `pkg/gui/types/views.go`: defines views
|
||||||
|
* `pkg/gui/views.go`: defines the ordering of views (front to back) and their initialisation code
|
||||||
|
* `pkg/gui/gui_common.go`: defines gui-specific methods that all controllers and helpers have access to
|
||||||
|
* `pkg/i18n/english.go`: defines the set of i18n strings and their English values
|
||||||
|
* `pkg/gui/controllers/helpers/refresh_helper.go`: manages refreshing of models. The refresh helper is typically invoked at the end of an action to re-load affected models from git (e.g. re-load branches after doing a git pull)
|
||||||
|
* `pkg/gui/controllers/quit_actions.go`: contains code that runs when you hit 'escape' on a view (assuming the view doesn't define its own escape handler)
|
||||||
|
* `vendor/github.com/jesseduffield/gocui/gui.go`: defines the gocui gui struct
|
||||||
|
* `vendor/github.com/jesseduffield/gocui/view.go`: defines the gocui view struct
|
||||||
|
|
||||||
|
## Concepts
|
||||||
|
|
||||||
|
* **View**: Views are defined in the gocui package, and they maintain an internal buffer of content which is rendered each time the screen is drawn.
|
||||||
|
* **Context**: A context is tied to a view and contains some additional state and logic specific to that view e.g. the branches context has code relating specifically to branches, and writes the list of branches to the branches view. Views and contexts share some responsibilities for historical reasons.
|
||||||
|
* **Controller**: A controller defined keybindings with associated handlers. One controller can be assigned to multiple contexts and one context can have multiple controllers. For example the list controller handles keybindings relating to navigating a list, and is assigned to all list contexts (e.g. the branches context).
|
||||||
|
* **Helper**: A helper defines shared code used by controllers, or used by some other parts of the application. Often a controller will have a method that ends up needing to be used by another controller, so in that case we move the method out into a helper so that both controllers can use it. We need to do this because controllers cannot refer to other controllers' methods.
|
||||||
|
|
||||||
|
In terms of dependencies, controllers sit at the highest level, so they can refer to helpers, contexts, and views (although it's preferable for view-specific code to live in contexts). Helpers can refer to contexts and views, and contexts can only refer to views. Views can't refer to contexts, controllers, or helpers.
|
||||||
|
|
||||||
|
* **Window**: A window is a section of the screen which will render a view. Windows are named after the default view that appears there, so for example there is a 'stash' window that is so named because by default the stash view appears there. But if you press enter on a stash entry, the stash entry's files will be shown in a different view, but in the same window.
|
||||||
|
* **Panel**: The term 'panel' is still used in a few places to refer to either a view or a window, and it's a term that is now deprecated in favour of 'view' and 'window'.
|
||||||
|
* **Tab**: Each tab in a window (e.g. Files, Worktrees, Submodules) actually has a corresponding view which we bring to the front upon changing tabs.
|
||||||
|
* **Model**: Representation of a git object e.g. commits, branches, files.
|
||||||
|
* **ViewModel**: Used by a context to maintain state related to the view.
|
||||||
|
* **Keybinding**: A keybinding associates a _key_ with an _action_. For example if you press the 'down' arrow, the action performed will be your cursor moving down a list by one.
|
||||||
|
* **Action**: An action is the thing that happens when you press a key. Often an action will invoke a git command, but not always: for example, navigation actions don't involve git.
|
||||||
|
* **Common structs**: Most structs have a field named `c` which contains a 'common' struct: a struct containing a bag of dependencies that most structs of the same layer require. For example if you want to access a helper from a controller you can do so with `self.c.Helpers.MyHelper`.
|
||||||
|
|
||||||
|
## Event loop and threads
|
||||||
|
|
||||||
|
The event loop is managed in the `MainLoop` function of `vendor/github.com/jesseduffield/gocui/gui.go`. Any time there is an event like a key press or a window resize, the event will be processed and then the screen will be redrawn. This involves calling the `layout` function defined in `pkg/gui/layout.go`, which lays out the windows and invokes some on-render hooks.
|
||||||
|
|
||||||
|
Often, as part of handling a keypress, we'll want to run some code asynchronously so that it doesn't block the UI thread. For this we'll typically run `self.c.OnWorker(myFunc)`. If the worker wants to then do something on the UI thread again it can call `self.c.OnUIThread(myOtherFunc)`.
|
||||||
|
|
||||||
|
## Legacy code structure
|
||||||
|
|
||||||
|
Before we had controllers and contexts, all the code lived directly in the gui package under a gui God Struct. This was fairly bloated and so we split things out to have a better separation of concerns. Nonetheless, it's a big effort to migrate all the code so we still have some logic in the gui struct that ought to live somewhere else. Likewise, we have some keybindings defined in `pkg/gui/keybindings.go` that ought to live on a controller (all keybindings used to be defined in that one file).
|
||||||
|
|
||||||
|
The new structure has its own problems: we don't have a clear guide on whether code should live in a controller or helper. The current approach is to put code in a controller until it's needed by another controller, and to then extract it out into a helper. We may be better off just putting code in helpers to start with and leaving controllers super-thin, with the responsibility of just pairing keys with corresponding helper functions. But it's not clear to me if that would be better than the current approach.
|
||||||
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# Demo Recordings
|
||||||
|
|
||||||
|
We want our demo recordings to be consistent and easy to update if we make changes to Lazygit's UI. Luckily for us, we have an existing recording system for the sake of our integration tests, so we can piggyback on that.
|
||||||
|
|
||||||
|
You'll want to familiarise yourself with how integration tests are written: see [here](../../pkg/integration/README.md).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Ideally we'd run this whole thing through docker but we haven't got that working. So you will need:
|
||||||
|
```
|
||||||
|
# for recording
|
||||||
|
npm i -g terminalizer
|
||||||
|
# for gif compression
|
||||||
|
npm i -g gifsicle
|
||||||
|
# for mp4 conversion
|
||||||
|
brew install ffmpeg
|
||||||
|
|
||||||
|
# font with icons
|
||||||
|
wget https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/DejaVuSansMono.tar.xz && \
|
||||||
|
tar -xf DejaVuSansMono.tar.xz -C /usr/local/share/fonts && \
|
||||||
|
rm DejaVuSansMono.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a demo
|
||||||
|
|
||||||
|
Demos are found in `pkg/integration/tests/demo/`. They are like regular integration tests but have `IsDemo: true` which has a few effects:
|
||||||
|
* The bottom row of the UI is quieter so that we can render captions
|
||||||
|
* Fetch/Push/Pull have artificial latency to mimic a network request
|
||||||
|
* The loader at the bottom-right does not appear
|
||||||
|
|
||||||
|
In demos, we don't need to be as strict in our assertions as we are in tests. But it's still good to have some basic assertions so that if we automate the process of updating demos we'll know if one of them has broken.
|
||||||
|
|
||||||
|
You can use the same flow as we use with integration tests when you're writing a demo:
|
||||||
|
* Setup the repo
|
||||||
|
* Run the demo in sandbox mode to get a feel of what needs to happen
|
||||||
|
* Come back and write the code to make it happen
|
||||||
|
|
||||||
|
### Adding captions
|
||||||
|
|
||||||
|
It's good to add captions explaining what task if being performed. Use the existing demos as a guide.
|
||||||
|
|
||||||
|
### Setting up the assets worktree
|
||||||
|
|
||||||
|
We store assets (which includes demo recordings) in the `assets` branch, which is a branch that shares no history with the main branch and exists purely for storing assets. Storing them separately means we don't clog up the code branches with large binaries.
|
||||||
|
|
||||||
|
The scripts and demo definitions live in the code branches but the output lives in the assets branch so to be able to create a video from a demo you'll need to create a linked worktree for the assets branch which you can do with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git worktree add .worktrees/assets assets
|
||||||
|
```
|
||||||
|
|
||||||
|
Outputs will be stored in `.worktrees/assets/demos/`. We'll store three separate things:
|
||||||
|
* the yaml of the recording
|
||||||
|
* the original gif
|
||||||
|
* either the compressed gif or the mp4 depending on the output you chose (see below)
|
||||||
|
|
||||||
|
### Recording the demo
|
||||||
|
|
||||||
|
Once you're happy with your demo you can record it using:
|
||||||
|
```sh
|
||||||
|
scripts/record_demo.sh [gif|mp4] <path>
|
||||||
|
# e.g.
|
||||||
|
scripts/record_demo.sh gif pkg/integration/tests/demo/interactive_rebase.go
|
||||||
|
```
|
||||||
|
|
||||||
|
~~The gif format is for use in the first video of the readme (it has a larger size but has auto-play and looping)~~
|
||||||
|
~~The mp4 format is for everything else (no looping, requires clicking, but smaller size).~~
|
||||||
|
|
||||||
|
Turns out that you can't store mp4s in a repo and link them from a README so we're gonna just use gifs across the board for now.
|
||||||
|
|
||||||
|
### Including demos in README/docs
|
||||||
|
|
||||||
|
If you've followed the above steps you'll end up with your output in your assets worktree.
|
||||||
|
|
||||||
|
Within that worktree, stage all three output files and raise a PR against the assets branch.
|
||||||
|
|
||||||
|
Then back in the code branch, in the doc, you can embed the recording like so:
|
||||||
|
```md
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
|
This means we can update assets without needing to update the docs that embed them.
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# About the mechanics of lazygit's "Find base commit for fixup" command
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
Lazygit has a command called "Find base commit for fixup" that helps with
|
||||||
|
creating fixup commits. (It is bound to "ctrl-f" by default, and I'll call it
|
||||||
|
simply "the ctrl-f command" throughout the rest of this text for brevity.)
|
||||||
|
|
||||||
|
It's a heuristic that needs to make a few assumptions; it tends to work well in
|
||||||
|
practice if users are aware of its limitations. The user-facing side of the
|
||||||
|
topic is explained [here](../Fixup_Commits.md). In this document we describe how
|
||||||
|
it works internally, and the design decisions behind it.
|
||||||
|
|
||||||
|
It is also interesting to compare it to the standalone tool
|
||||||
|
[git-absorb](https://github.com/tummychow/git-absorb) which does a very similar
|
||||||
|
thing, but made different decisions in some cases. We'll explore these
|
||||||
|
differences in this document.
|
||||||
|
|
||||||
|
## Design goals
|
||||||
|
|
||||||
|
I'll start with git-absorb's design goals (my interpretation, since I can't
|
||||||
|
speak for git-absorb's maintainer of course): its main goal seems to be minimum
|
||||||
|
user interaction required. The idea is that you have a PR in review, the
|
||||||
|
reviewer requested a bunch of changes, you make all these changes, so you have a
|
||||||
|
working copy with lots of modified files, and then you fire up git-absorb and it
|
||||||
|
creates all the necessary fixup commits automatically with no further user
|
||||||
|
intervention.
|
||||||
|
|
||||||
|
While this sounds attractive, it conflicts with ctrl-f's main design goal, which
|
||||||
|
is to support creating high-quality fixups. My philosophy is that fixup commits
|
||||||
|
should have the same high quality standards as normal commits; in particular:
|
||||||
|
|
||||||
|
- they should be atomic. This means that multiple diff hunks that belong
|
||||||
|
together to form one logical change should be in the same fixup commit. (Not
|
||||||
|
always possible if the logical change needs to be fixed up into several
|
||||||
|
different base commits.)
|
||||||
|
- they should be minimal. Every fixup commit should ideally contain only one
|
||||||
|
logical change, not several unrelated ones.
|
||||||
|
|
||||||
|
Why is this important? Because fixup commits are mainly a tool for reviewing (if
|
||||||
|
they weren't, you might as well squash the changes into their base commits right
|
||||||
|
away). And reviewing fixup commits is easier if they are well-structured, just
|
||||||
|
like normal commits.
|
||||||
|
|
||||||
|
The only way to achieve this with git-absorb is to set the `oneFixupPerCommit`
|
||||||
|
config option (for the first goal), and then manually stage the changes that
|
||||||
|
belong together (for the second). This is close to what you have to do with
|
||||||
|
ctrl-f, with one exception that we'll get to below.
|
||||||
|
|
||||||
|
But ctrl-f enforces this by refusing to do the job if the staged hunks belong to
|
||||||
|
more than one base commit. Git-absorb will happily create multiple fixup commits
|
||||||
|
in this case; ctrl-f doesn't, to enforce that you pay attention to how you group
|
||||||
|
the changes. There's another reason for this behavior: ctrl-f doesn't create
|
||||||
|
fixup commits itself (unlike git-absorb), instead it just selects the found base
|
||||||
|
commit so that the user can decide whether to amend the changes right in, or
|
||||||
|
create a fixup commit from there (both are single-key commands in lazygit). And
|
||||||
|
lazygit doesn't support non-contiguous multiselections of commits, but even if
|
||||||
|
it did, it wouldn't help much in this case.
|
||||||
|
|
||||||
|
## The mechanics
|
||||||
|
|
||||||
|
### General approach
|
||||||
|
|
||||||
|
Git-absorb uses a relatively simple approach, and the benefit is of course that
|
||||||
|
it is easy to understand: it looks at every diff hunk separately, and for every
|
||||||
|
hunk it looks at all commits (starting from the newest one backwards) to find
|
||||||
|
the earliest commit that the change can be amended to without conflicts.
|
||||||
|
|
||||||
|
It is important to realize that "diff hunk" doesn't necessarily mean what you
|
||||||
|
see in the diff view. Git-absorb and ctrl-f both use a context of 0 when diffing
|
||||||
|
your code, so they often see more and smaller hunks than users do. For example,
|
||||||
|
moving a line of code down by one line is a single hunk for users, but it's two
|
||||||
|
separate hunks for git-absorb and ctrl-f; one for deleting the line at the old
|
||||||
|
place, and another one for adding the line at the new place, even if it's only
|
||||||
|
one line further down.
|
||||||
|
|
||||||
|
From this, it follows that there's one big problem with git-absorb's approach:
|
||||||
|
when moving code, it doesn't realize that the two related hunks of deleting the
|
||||||
|
code from the old place and inserting it at the new place belong together, and
|
||||||
|
often it will manage to create a fixup commit for the first hunk, but leave the
|
||||||
|
other hunk in your working copy as "don't know what to do with this". As an
|
||||||
|
example, suppose your PR is adding a line of code to an existing function, maybe
|
||||||
|
one that declares a new variable, and a reviewer suggests to move this line down
|
||||||
|
a bit, closer to where some other related variables are declared. Moving the
|
||||||
|
line down results in two diff hunks (from the perspective of git-absorb and
|
||||||
|
ctrl-f, as they both use a context of 0 when diffing), and when looking at the
|
||||||
|
second diff hunk in isolation there's no way to find a base commit in your PR
|
||||||
|
for it, because the surrounding code is already on main.
|
||||||
|
|
||||||
|
To solve this, the ctrl-f command makes a distinction between hunks that have
|
||||||
|
deleted lines and hunks that have only added lines. If the whole diff contains
|
||||||
|
any hunks that have deleted lines, it uses only those hunks to determine the
|
||||||
|
base commit, and then assumes that all the hunks that have only added lines
|
||||||
|
belong into the same commit. This nicely solves the above example of moving
|
||||||
|
code, but also other examples such as the following:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to show example</summary>
|
||||||
|
|
||||||
|
Suppose you have a PR in which you added the following function:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func findCommit(hash string) (*models.Commit, int, bool) {
|
||||||
|
for i, commit := range self.c.Model().Commits {
|
||||||
|
if commit.Hash == hash {
|
||||||
|
return commit, i, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, -1, false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A reviewer suggests to replace the manual `for` loop with a call to
|
||||||
|
`lo.FindIndexOf` since that's less code and more idiomatic. So your modification
|
||||||
|
is this:
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- a/my_file.go
|
||||||
|
+++ b/my_file.go
|
||||||
|
@@ -12,2 +12,3 @@ import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
+ "github.com/samber/lo"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
@@ -308,9 +309,5 @@ func (self *FixupHelper) blameAddedLines(addedLineHunks []*hunk) ([]string, erro
|
||||||
|
func findCommit(hash string) (*models.Commit, int, bool) {
|
||||||
|
- for i, commit := range self.c.Model().Commits {
|
||||||
|
- if commit.Hash == hash {
|
||||||
|
- return commit, i, true
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return nil, -1, false
|
||||||
|
+ return lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool {
|
||||||
|
+ return commit.Hash == hash
|
||||||
|
+ })
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If we were to look at these two hunks separately, we'd easily find the base
|
||||||
|
commit for the second one, but we wouldn't find the one for the first hunk
|
||||||
|
because the imports around the added import have been on main for a long time.
|
||||||
|
In fact, git-absorb leaves this hunk in the working copy because it doesn't know
|
||||||
|
what to do with it.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Only if there are no hunks with deleted lines does ctrl-f look at the hunks with
|
||||||
|
only added lines and determines the base commit for them. This solves cases like
|
||||||
|
adding a comment above a function that you added in your PR.
|
||||||
|
|
||||||
|
The downside of this more complicated approach is that it relies on the user
|
||||||
|
staging related hunks correctly. However, in my experience this is easy to do
|
||||||
|
and not very error-prone, as long as users are aware of this behavior. Lazygit
|
||||||
|
tries to help making them aware of it by showing a warning whenever there are
|
||||||
|
hunks with only added lines in addition to hunks with deleted lines.
|
||||||
|
|
||||||
|
### Finding the base commit for a given hunk
|
||||||
|
|
||||||
|
As explained above, git-absorb finds the base commit by walking the commits
|
||||||
|
backwards until it finds one that conflicts with the hunk, and then the found
|
||||||
|
base commit is the one just before that one. This works reliably, but it is
|
||||||
|
slow.
|
||||||
|
|
||||||
|
Ctrl-f uses a different approach that is usually much faster, but should always
|
||||||
|
yield the same result. Again, it makes a distinction between hunks with deleted
|
||||||
|
lines and hunks with only added lines. For hunks with deleted lines it performs
|
||||||
|
a line range blame for all the deleted lines (e.g. `git blame -L42,+3 --
|
||||||
|
filename`), and if the result is the same for all deleted lines, then that's the
|
||||||
|
base commit; otherwise it returns an error.
|
||||||
|
|
||||||
|
For hunks with only added lines, it gets a little more complicated. We blame the
|
||||||
|
single lines just before and just after the hunk (I'll ignore the edge cases of
|
||||||
|
either of those not existing because the hunk is at the beginning or end of the
|
||||||
|
file; read the code to see how we handle these cases). If the blame result is
|
||||||
|
the same for both, then that's the base commit. This is the case of adding a
|
||||||
|
line in the middle of a block of code that was added in the PR. Otherwise, the
|
||||||
|
base commit is the more recent of the two (and in this case it doesn't matter if
|
||||||
|
the other one is an earlier commit in the current branch, or a possibly very old
|
||||||
|
commit that's already on main). This covers the common case of adding a comment
|
||||||
|
to a function that was added in the PR, but also adding another line at the end
|
||||||
|
of a block of code that was added in the base commit.
|
||||||
|
|
||||||
|
It's interesting to discuss what "more recent" means here. You could say if
|
||||||
|
commit A is an ancestor of commit B (or in other words, A is reachable from B)
|
||||||
|
then B is the more recent one. And if none of the two commits is reachable from
|
||||||
|
the other, you have an error case because it's unclear which of the two should
|
||||||
|
be considered the base commit. The scenario in which this happens is a commit
|
||||||
|
history like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
C---D
|
||||||
|
/ \
|
||||||
|
A---B---E---F---G
|
||||||
|
```
|
||||||
|
|
||||||
|
where, for instance, D and E are the two blame results.
|
||||||
|
|
||||||
|
Unfortunately, determining the ancestry relationship between two commits using
|
||||||
|
git commands is a bit expensive and not totally straightforward. Fortunately,
|
||||||
|
it's not necessary in lazygit because lazygit has the most recent 300 commits
|
||||||
|
cached in memory, and can simply search its linear list of commits to see which
|
||||||
|
one is closer to the beginning of the list. If only one of the two commits is
|
||||||
|
found within those 300 commits, then that's the more recent one; if neither is
|
||||||
|
found, we assume that both commits are on main and error out. In the merge
|
||||||
|
scenario pictured above, we arbitrarily return one of the two commits (this will
|
||||||
|
depend on the log order), but that's probably fine as this scenario should be
|
||||||
|
extremely rare in practice; in most cases, feature branches are simply linear.
|
||||||
|
|
||||||
|
### Knowing where to stop searching
|
||||||
|
|
||||||
|
Git-absorb needs to know when to stop walking backwards searching for commits,
|
||||||
|
since it doesn't make sense to create fixups for commits that are already on
|
||||||
|
main. However, it doesn't know where the current branch ends and main starts, so
|
||||||
|
it needs to rely on user input for this. By default it searches the most recent
|
||||||
|
10 commits, but this can be overridden with a config setting. In longer branches
|
||||||
|
this is often not enough for finding the base commit; but setting it to a higher
|
||||||
|
value causes the command to take longer to complete when the base commit can't
|
||||||
|
be found.
|
||||||
|
|
||||||
|
Lazygit doesn't have this problem. For a given blame result it needs to
|
||||||
|
determine whether that commit is already on main, and if it can find the commit
|
||||||
|
in its cached list of the first 300 commits it can get that information from
|
||||||
|
there, because lazygit knows what the user's configured main branches are
|
||||||
|
(`master` and `main` by default, but it could also include branches like `devel`
|
||||||
|
or `1.0-hotfixes`), and so it can tell for each commit whether it's contained in
|
||||||
|
one of those main branches. And if it can't find it among the first 300 commits,
|
||||||
|
it assumes the commit already on main, on the assumption that no feature branch
|
||||||
|
has more than 300 commits.
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Profiling Lazygit
|
||||||
|
|
||||||
|
If you want to investigate what's contributing to CPU or memory usage, start
|
||||||
|
lazygit with the `-profile` command line flag. This tells it to start an
|
||||||
|
integrated web server that listens for profiling requests.
|
||||||
|
|
||||||
|
## Save profile data
|
||||||
|
|
||||||
|
### CPU
|
||||||
|
|
||||||
|
While lazygit is running with the `-profile` flag, perform a CPU profile and
|
||||||
|
save it to a file by running this command in another terminal window:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -o cpu.out http://127.0.0.1:6060/debug/pprof/profile
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, it profiles for 30 seconds. To change the duration, use
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -o cpu.out 'http://127.0.0.1:6060/debug/pprof/profile?seconds=60'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory
|
||||||
|
|
||||||
|
To save a heap profile (containing information about all memory allocated so
|
||||||
|
far since startup), use
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -o mem.out http://127.0.0.1:6060/debug/pprof/heap
|
||||||
|
```
|
||||||
|
|
||||||
|
Sometimes it can be useful to get a delta log, i.e. to see how memory usage
|
||||||
|
developed from one point in time to another. For that, use
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -o mem.out 'http://127.0.0.1:6060/debug/pprof/heap?seconds=20'
|
||||||
|
```
|
||||||
|
|
||||||
|
This will log the memory usage difference between now and 20 seconds later, so
|
||||||
|
it gives you 20 seconds to perform the action in lazygit that you are interested
|
||||||
|
in measuring.
|
||||||
|
|
||||||
|
## View profile data
|
||||||
|
|
||||||
|
To display the profile data, you can either use speedscope.app, or the pprof
|
||||||
|
tool that comes with go. I prefer the former because it has a nicer UI and is a
|
||||||
|
little more powerful; however, I have seen cases where it wasn't able to load a
|
||||||
|
profile for some reason, in which case it's good to have the pprof tool as a
|
||||||
|
fallback.
|
||||||
|
|
||||||
|
### Speedscope.app
|
||||||
|
|
||||||
|
Go to https://www.speedscope.app/ in your browser, and drag the saved profile
|
||||||
|
onto the browser window. Refer to [the
|
||||||
|
documentation](https://github.com/jlfwong/speedscope?tab=readme-ov-file#usage)
|
||||||
|
for how to navigate the data.
|
||||||
|
|
||||||
|
### Pprof tool
|
||||||
|
|
||||||
|
To view a profile that you saved as `cpu.out`, use
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go tool pprof -http=:8080 cpu.out
|
||||||
|
```
|
||||||
|
|
||||||
|
By default this shows the graph view, which I don't find very useful myself.
|
||||||
|
Choose "Flame Graph" from the View menu to show a much more useful
|
||||||
|
representation of the data.
|
||||||
+5
-1
@@ -1,4 +1,8 @@
|
|||||||
# Dev Documentation Overview
|
# Dev Documentation Overview
|
||||||
|
|
||||||
* [Busy/Idle tracking](./Busy.md).
|
* [Codebase Guide](./Codebase_Guide.md)
|
||||||
|
* [Busy/Idle Tracking](./Busy.md)
|
||||||
* [Integration Tests](../../pkg/integration/README.md)
|
* [Integration Tests](../../pkg/integration/README.md)
|
||||||
|
* [Demo Recordings](./Demo_Recordings.md)
|
||||||
|
* [Find base commit for fixup design](Find_Base_Commit_For_Fixup_Design.md)
|
||||||
|
* [Profiling](Profiling.md)
|
||||||
|
|||||||
+302
-266
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit Keybindings
|
# Lazygit Keybindings
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
## Global keybindings
|
## Global keybindings
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: Switch to a recent repo
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: Scroll up main panel (fn+up/shift+k)
|
| `` <c-r> `` | Switch to a recent repo | |
|
||||||
<kbd><pgdown></kbd>: Scroll down main panel (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | Scroll up main window | |
|
||||||
<kbd>@</kbd>: Open command log menu
|
| `` <pgdown> (fn+down/shift+j) `` | Scroll down main window | |
|
||||||
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
|
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: Execute custom command
|
| `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: View custom patch options
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: View merge/rebase options
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: Refresh
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: Next screen mode (normal/half/fullscreen)
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: Prev screen mode
|
| `` : `` | Execute custom command | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: Open menu
|
| `` <c-p> `` | View custom patch options | |
|
||||||
<kbd><c-s></kbd>: View filter-by-path options
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: Open diff menu
|
| `` R `` | Refresh | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: Open diff menu
|
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
||||||
<kbd><c-w></kbd>: Toggle whether or not whitespace changes are shown in the diff view
|
| `` _ `` | Prev screen mode | |
|
||||||
<kbd>z</kbd>: Undo
|
| `` ? `` | Open keybindings menu | |
|
||||||
<kbd><c-z></kbd>: Redo
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: Push
|
| `` W `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: Pull
|
| `` <c-e> `` | View diffing options | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | Quit | |
|
||||||
|
| `` <esc> `` | Cancel | |
|
||||||
|
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | Undo | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
| `` <c-z> `` | Redo | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
|
||||||
## List panel navigation
|
## List panel navigation
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: Previous page
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: Next page
|
| `` , `` | Previous page | |
|
||||||
<kbd><</kbd>: Scroll to top
|
| `` . `` | Next page | |
|
||||||
<kbd>></kbd>: Scroll to bottom
|
| `` < `` | Scroll to top | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` > `` | Scroll to bottom | |
|
||||||
<kbd>H</kbd>: Scroll left
|
| `` v `` | Toggle range select | |
|
||||||
<kbd>L</kbd>: Scroll right
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: Next tab
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: Previous tab
|
| `` / `` | Search the current view by text | |
|
||||||
</pre>
|
| `` H `` | Scroll left | |
|
||||||
|
| `` L `` | Scroll right | |
|
||||||
|
| `` ] `` | Next tab | |
|
||||||
|
| `` [ `` | Previous tab | |
|
||||||
|
|
||||||
## Commit files
|
## Commit files
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy the committed file name to the clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Checkout file
|
| `` <c-o> `` | Copy path to clipboard | |
|
||||||
<kbd>d</kbd>: Discard this commit's changes to this file
|
| `` c `` | Checkout | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||||
<kbd>o</kbd>: Open file
|
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
|
||||||
<kbd>e</kbd>: Edit file
|
| `` o `` | Open file | Open file in default application. |
|
||||||
<kbd><space></kbd>: Toggle file included in patch
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
| `` <space> `` | Toggle file included in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | Toggle file tree view | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Commit summary
|
## Commit summary
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Confirm
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Close
|
| `` <enter> `` | Confirm | |
|
||||||
</pre>
|
| `` <esc> `` | Close | |
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
<kbd>b</kbd>: View bisect options
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd>s</kbd>: Squash down
|
| `` b `` | View bisect options | |
|
||||||
<kbd>f</kbd>: Fixup commit
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: Reword commit
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: Reword commit with editor
|
| `` r `` | Reword | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: Delete commit
|
| `` R `` | Reword with editor | |
|
||||||
<kbd>e</kbd>: Edit commit
|
| `` d `` | Drop | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: Pick commit (when mid-rebase)
|
| `` e `` | Edit (start interactive rebase) | Edit the selected commit. Use this to start an interactive rebase from the selected commit. When already mid-rebase, this will mark the selected commit for editing, which means that upon continuing the rebase, the rebase will pause at the selected commit to allow you to make changes. |
|
||||||
<kbd>F</kbd>: Create fixup commit for this commit
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: Move commit down one
|
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
|
||||||
<kbd><c-k></kbd>: Move commit up one
|
| `` F `` | Create fixup commit | Create 'fixup!' commit for the selected commit. Later on, you can press `S` on this same commit to apply all above fixup commits. |
|
||||||
<kbd>v</kbd>: Paste commits (cherry-pick)
|
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
||||||
<kbd>A</kbd>: Amend commit with staged changes
|
| `` <c-j> `` | Move commit down one | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | Move commit up one | |
|
||||||
<kbd>t</kbd>: Revert commit
|
| `` V `` | Paste (cherry-pick) | |
|
||||||
<kbd>T</kbd>: Tag commit
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: Open log menu
|
| `` A `` | Amend | Amend commit with staged changes. If the selected commit is the HEAD commit, this will perform `git commit --amend`. Otherwise the commit will be amended via a rebase. |
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` <c-l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: Copy commit (cherry-pick)
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` n `` | Create new branch off of commit | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | View files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Confirmation panel
|
## Confirmation panel
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Confirm
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Close/Cancel
|
| `` <enter> `` | Confirm | |
|
||||||
</pre>
|
| `` <esc> `` | Close/Cancel | |
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: View 'discard changes' options
|
| `` <c-o> `` | Copy path to clipboard | |
|
||||||
<kbd><space></kbd>: Toggle staged
|
| `` <space> `` | Stage | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: Filter files by status
|
| `` <c-b> `` | Filter files by status | |
|
||||||
<kbd>c</kbd>: Commit changes
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
| `` c `` | Commit | Commit staged changes. |
|
||||||
<kbd>A</kbd>: Amend last commit
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
<kbd>C</kbd>: Commit changes using git editor
|
| `` A `` | Amend last commit | |
|
||||||
<kbd>e</kbd>: Edit file
|
| `` C `` | Commit changes using git editor | |
|
||||||
<kbd>o</kbd>: Open file
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: Ignore or exclude file
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: Refresh files
|
| `` o `` | Open file | Open file in default application. |
|
||||||
<kbd>s</kbd>: Stash all changes
|
| `` i `` | Ignore or exclude file | |
|
||||||
<kbd>S</kbd>: View stash options
|
| `` r `` | Refresh files | |
|
||||||
<kbd>a</kbd>: Stage/unstage all
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
|
| `` S `` | View stash options | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: View upstream reset options
|
| `` a `` | Stage all | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: View reset options
|
| `` <enter> `` | Stage lines / Collapse directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
| `` g `` | View upstream reset options | |
|
||||||
<kbd>f</kbd>: Fetch
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` ` `` | Toggle file tree view | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Local branches
|
## Local branches
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy branch name to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Show git-flow options
|
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||||
<kbd><space></kbd>: Checkout
|
| `` i `` | Show git-flow options | |
|
||||||
<kbd>n</kbd>: New branch
|
| `` <space> `` | Checkout | Checkout selected item. |
|
||||||
<kbd>o</kbd>: Create pull request
|
| `` n `` | New branch | |
|
||||||
<kbd>O</kbd>: Create pull request options
|
| `` o `` | Create pull request | |
|
||||||
<kbd><c-y></kbd>: Copy pull request URL to clipboard
|
| `` O `` | View create pull request options | |
|
||||||
<kbd>c</kbd>: Checkout by name
|
| `` <c-y> `` | Copy pull request URL to clipboard | |
|
||||||
<kbd>F</kbd>: Force checkout
|
| `` c `` | Checkout by name | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: Delete branch
|
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: Merge into currently checked out branch
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: Fast-forward this branch from its upstream
|
| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: Create tag
|
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` T `` | New tag | |
|
||||||
<kbd>R</kbd>: Rename branch
|
| `` s `` | Sort order | |
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
| `` g `` | Reset | |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` R `` | Rename branch | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Main panel (merging)
|
## Main panel (merging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: Edit file
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: Open file
|
| `` <space> `` | Pick hunk | |
|
||||||
<kbd><left></kbd>: Select previous conflict
|
| `` b `` | Pick all hunks | |
|
||||||
<kbd><right></kbd>: Select next conflict
|
| `` <up> `` | Previous hunk | |
|
||||||
<kbd><up></kbd>: Select previous hunk
|
| `` <down> `` | Next hunk | |
|
||||||
<kbd><down></kbd>: Select next hunk
|
| `` <left> `` | Previous conflict | |
|
||||||
<kbd>z</kbd>: Undo
|
| `` <right> `` | Next conflict | |
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
| `` z `` | Undo | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: Pick hunk
|
| `` e `` | Edit file | Open file in external editor. |
|
||||||
<kbd>b</kbd>: Pick all hunks
|
| `` o `` | Open file | Open file in default application. |
|
||||||
<kbd><esc></kbd>: Return to files panel
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | Return to files panel | |
|
||||||
|
|
||||||
## Main panel (normal)
|
## Main panel (normal)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: Scroll down (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: Scroll up (fn+down)
|
| `` mouse wheel down (fn+up) `` | Scroll down | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | Scroll up | |
|
||||||
|
|
||||||
## Main panel (patch building)
|
## Main panel (patch building)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Select previous hunk
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Select next hunk
|
| `` <left> `` | Go to previous hunk | |
|
||||||
<kbd>v</kbd>: Toggle drag select
|
| `` <right> `` | Go to next hunk | |
|
||||||
<kbd>V</kbd>: Toggle drag select
|
| `` v `` | Toggle range select | |
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
| `` a `` | Select hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
<kbd>o</kbd>: Open file
|
| `` o `` | Open file | Open file in default application. |
|
||||||
<kbd>e</kbd>: Edit file
|
| `` e `` | Edit file | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Add/Remove line(s) to patch
|
| `` <space> `` | Toggle lines in patch | |
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
| `` <esc> `` | Exit custom patch builder | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` / `` | Search the current view by text | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Main panel (staging)
|
## Main panel (staging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Select previous hunk
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Select next hunk
|
| `` <left> `` | Go to previous hunk | |
|
||||||
<kbd>v</kbd>: Toggle drag select
|
| `` <right> `` | Go to next hunk | |
|
||||||
<kbd>V</kbd>: Toggle drag select
|
| `` v `` | Toggle range select | |
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
| `` a `` | Select hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
<kbd>o</kbd>: Open file
|
| `` <space> `` | Stage | Toggle selection staged / unstaged. |
|
||||||
<kbd>e</kbd>: Edit file
|
| `` d `` | Discard | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: Return to files panel
|
| `` o `` | Open file | Open file in default application. |
|
||||||
<kbd><tab></kbd>: Switch to other panel (staged/unstaged changes)
|
| `` e `` | Edit file | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Toggle line staged / unstaged
|
| `` <esc> `` | Return to files panel | |
|
||||||
<kbd>d</kbd>: Discard change (git reset)
|
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Edit hunk
|
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: Commit changes
|
| `` c `` | Commit | Commit staged changes. |
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
<kbd>C</kbd>: Commit changes using git editor
|
| `` C `` | Commit changes using git editor | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Execute
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Close
|
| `` <enter> `` | Execute | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | Close | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | Create new branch off of commit | |
|
||||||
<kbd>c</kbd>: Copy commit (cherry-pick)
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
| `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | View commits | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Remote branches
|
## Remote branches
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy branch name to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout
|
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||||
<kbd>n</kbd>: New branch
|
| `` <space> `` | Checkout | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: Merge into currently checked out branch
|
| `` n `` | New branch | |
|
||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: Delete branch
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` s `` | Sort order | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Remotes
|
## Remotes
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: Fetch remote
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: Add new remote
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: Remove remote
|
| `` n `` | New remote | |
|
||||||
<kbd>e</kbd>: Edit remote
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | Edit the selected remote's name or URL. |
|
||||||
</pre>
|
| `` f `` | Fetch | Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Apply
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Pop
|
| `` <space> `` | Apply | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: Drop
|
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: New branch
|
| `` d `` | Drop | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Rename stash
|
| `` n `` | New branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` r `` | Rename stash | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | View files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: Open config file
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: Edit config file
|
| `` o `` | Open config file | Open file in default application. |
|
||||||
<kbd>u</kbd>: Check for update
|
| `` e `` | Edit config file | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: Switch to a recent repo
|
| `` u `` | Check for update | |
|
||||||
<kbd>a</kbd>: Show all branch logs
|
| `` <enter> `` | Switch to a recent repo | |
|
||||||
</pre>
|
| `` a `` | Show/cycle all branch logs | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | Create new branch off of commit | |
|
||||||
<kbd>c</kbd>: Copy commit (cherry-pick)
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
| `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` <enter> `` | View files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy submodule name to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: Enter submodule
|
| `` <c-o> `` | Copy submodule name to clipboard | |
|
||||||
<kbd>d</kbd>: Remove submodule
|
| `` <enter> `` | Enter | Enter submodule. After entering the submodule, you can press `<esc>` to escape back to the parent repo. |
|
||||||
<kbd>u</kbd>: Update submodule
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: Add new submodule
|
| `` u `` | Update | Update selected submodule. |
|
||||||
<kbd>e</kbd>: Update submodule URL
|
| `` n `` | New submodule | |
|
||||||
<kbd>i</kbd>: Initialize submodule
|
| `` e `` | Update submodule URL | |
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
| `` i `` | Initialize | Initialize the selected submodule to prepare for fetching. You probably want to follow this up by invoking the 'update' action to fetch the submodule. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | View bulk submodule options | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Checkout
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Delete tag
|
| `` <space> `` | Checkout | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: Push tag
|
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Create tag
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
+302
-266
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit キーバインド
|
# Lazygit キーバインド
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
## グローバルキーバインド
|
## グローバルキーバインド
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: 最近使用したリポジトリに切り替え
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: メインパネルを上にスクロール (fn+up/shift+k)
|
| `` <c-r> `` | 最近使用したリポジトリに切り替え | |
|
||||||
<kbd><pgdown></kbd>: メインパネルを下にスクロール (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | メインパネルを上にスクロール | |
|
||||||
<kbd>@</kbd>: コマンドログメニューを開く
|
| `` <pgdown> (fn+down/shift+j) `` | メインパネルを下にスクロール | |
|
||||||
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
|
| `` @ `` | コマンドログメニューを開く | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: カスタムコマンドを実行
|
| `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: View custom patch options
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: View merge/rebase options
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: リフレッシュ
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: 次のスクリーンモード (normal/half/fullscreen)
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: 前のスクリーンモード
|
| `` : `` | カスタムコマンドを実行 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: メニューを開く
|
| `` <c-p> `` | View custom patch options | |
|
||||||
<kbd><c-s></kbd>: View filter-by-path options
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: 差分メニューを開く
|
| `` R `` | リフレッシュ | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: 差分メニューを開く
|
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
||||||
<kbd><c-w></kbd>: 空白文字の差分の表示有無を切り替え
|
| `` _ `` | 前のスクリーンモード | |
|
||||||
<kbd>z</kbd>: アンドゥ (via reflog) (experimental)
|
| `` ? `` | メニューを開く | |
|
||||||
<kbd><c-z></kbd>: リドゥ (via reflog) (experimental)
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: Push
|
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: Pull
|
| `` <c-e> `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | 終了 | |
|
||||||
|
| `` <esc> `` | キャンセル | |
|
||||||
|
| `` <c-w> `` | 空白文字の差分の表示有無を切り替え | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | アンドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
| `` <c-z> `` | リドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
|
||||||
## 一覧パネルの操作
|
## 一覧パネルの操作
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: 前のページ
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: 次のページ
|
| `` , `` | 前のページ | |
|
||||||
<kbd><</kbd>: 最上部までスクロール
|
| `` . `` | 次のページ | |
|
||||||
<kbd>></kbd>: 最下部までスクロール
|
| `` < `` | 最上部までスクロール | |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` > `` | 最下部までスクロール | |
|
||||||
<kbd>H</kbd>: 左スクロール
|
| `` v `` | 範囲選択を切り替え | |
|
||||||
<kbd>L</kbd>: 右スクロール
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: 次のタブ
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: 前のタブ
|
| `` / `` | 検索を開始 | |
|
||||||
</pre>
|
| `` H `` | 左スクロール | |
|
||||||
|
| `` L `` | 右スクロール | |
|
||||||
|
| `` ] `` | 次のタブ | |
|
||||||
|
| `` [ `` | 前のタブ | |
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 適用
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Pop
|
| `` <space> `` | 適用 | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: Drop
|
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: 新しいブランチを作成
|
| `` d `` | Drop | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Stashを変更
|
| `` n `` | 新しいブランチを作成 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` r `` | Stashを変更 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | View files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: コミットのSHAをクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: コミットをチェックアウト
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
<kbd>y</kbd>: コミットの情報をコピー
|
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: ブラウザでコミットを開く
|
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: コミットにブランチを作成
|
| `` o `` | ブラウザでコミットを開く | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | コミットにブランチを作成 | |
|
||||||
<kbd>c</kbd>: コミットをコピー (cherry-pick)
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` <enter> `` | View files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## コミット
|
## コミット
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: コミットのSHAをクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
<kbd>b</kbd>: View bisect options
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd>s</kbd>: Squash down
|
| `` b `` | View bisect options | |
|
||||||
<kbd>f</kbd>: Fixup commit
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: コミットメッセージを変更
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: エディタでコミットメッセージを編集
|
| `` r `` | コミットメッセージを変更 | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: コミットを削除
|
| `` R `` | エディタでコミットメッセージを編集 | |
|
||||||
<kbd>e</kbd>: コミットを編集
|
| `` d `` | コミットを削除 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: Pick commit (when mid-rebase)
|
| `` e `` | Edit (start interactive rebase) | コミットを編集 |
|
||||||
<kbd>F</kbd>: このコミットに対するfixupコミットを作成
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: コミットを1つ下に移動
|
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
|
||||||
<kbd><c-k></kbd>: コミットを1つ上に移動
|
| `` F `` | Fixupコミットを作成 | このコミットに対するfixupコミットを作成 |
|
||||||
<kbd>v</kbd>: コミットを貼り付け (cherry-pick)
|
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
||||||
<kbd>A</kbd>: ステージされた変更でamendコミット
|
| `` <c-j> `` | コミットを1つ下に移動 | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | コミットを1つ上に移動 | |
|
||||||
<kbd>t</kbd>: コミットをrevert
|
| `` V `` | コミットを貼り付け (cherry-pick) | |
|
||||||
<kbd>T</kbd>: タグを作成
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: ログメニューを開く
|
| `` A `` | Amend | ステージされた変更でamendコミット |
|
||||||
<kbd><space></kbd>: コミットをチェックアウト
|
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: コミットの情報をコピー
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: ブラウザでコミットを開く
|
| `` T `` | タグを作成 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: コミットにブランチを作成
|
| `` <c-l> `` | ログメニューを開く | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: コミットをコピー (cherry-pick)
|
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
| `` o `` | ブラウザでコミットを開く | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` n `` | コミットにブランチを作成 | |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | View files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## コミットファイル
|
## コミットファイル
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: コミットされたファイル名をクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Checkout file
|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
||||||
<kbd>d</kbd>: Discard this commit's changes to this file
|
| `` c `` | チェックアウト | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||||
<kbd>o</kbd>: ファイルを開く
|
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
|
||||||
<kbd>e</kbd>: ファイルを編集
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
<kbd><space></kbd>: Toggle file included in patch
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
| `` <space> `` | Toggle file included in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## コミットメッセージ
|
## コミットメッセージ
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 確認
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 閉じる
|
| `` <enter> `` | 確認 | |
|
||||||
</pre>
|
| `` <esc> `` | 閉じる | |
|
||||||
|
|
||||||
## サブモジュール
|
## サブモジュール
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: サブモジュール名をクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: サブモジュールを開く
|
| `` <c-o> `` | サブモジュール名をクリップボードにコピー | |
|
||||||
<kbd>d</kbd>: サブモジュールを削除
|
| `` <enter> `` | Enter | サブモジュールを開く |
|
||||||
<kbd>u</kbd>: サブモジュールを更新
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: サブモジュールを新規追加
|
| `` u `` | Update | サブモジュールを更新 |
|
||||||
<kbd>e</kbd>: サブモジュールのURLを更新
|
| `` n `` | サブモジュールを新規追加 | |
|
||||||
<kbd>i</kbd>: サブモジュールを初期化
|
| `` e `` | サブモジュールのURLを更新 | |
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
| `` i `` | Initialize | サブモジュールを初期化 |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | View bulk submodule options | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## ステータス
|
## ステータス
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: 設定ファイルを開く
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: 設定ファイルを編集
|
| `` o `` | 設定ファイルを開く | Open file in default application. |
|
||||||
<kbd>u</kbd>: 更新を確認
|
| `` e `` | 設定ファイルを編集 | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: 最近使用したリポジトリに切り替え
|
| `` u `` | 更新を確認 | |
|
||||||
<kbd>a</kbd>: すべてのブランチログを表示
|
| `` <enter> `` | 最近使用したリポジトリに切り替え | |
|
||||||
</pre>
|
| `` a `` | すべてのブランチログを表示 | |
|
||||||
|
|
||||||
## タグ
|
## タグ
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: チェックアウト
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: タグを削除
|
| `` <space> `` | チェックアウト | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: タグをpush
|
| `` n `` | タグを作成 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: タグを作成
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## ファイル
|
## ファイル
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: ファイル名をクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: View 'discard changes' options
|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
||||||
<kbd><space></kbd>: ステージ/アンステージ
|
| `` <space> `` | ステージ/アンステージ | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: ファイルをフィルタ (ステージ/アンステージ)
|
| `` <c-b> `` | ファイルをフィルタ (ステージ/アンステージ) | |
|
||||||
<kbd>c</kbd>: 変更をコミット
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
|
| `` c `` | 変更をコミット | Commit staged changes. |
|
||||||
<kbd>A</kbd>: 最新のコミットにamend
|
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
||||||
<kbd>C</kbd>: gitエディタを使用して変更をコミット
|
| `` A `` | 最新のコミットにamend | |
|
||||||
<kbd>e</kbd>: ファイルを編集
|
| `` C `` | gitエディタを使用して変更をコミット | |
|
||||||
<kbd>o</kbd>: ファイルを開く
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: ファイルをignore
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: ファイルをリフレッシュ
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
<kbd>s</kbd>: 変更をstash
|
| `` i `` | ファイルをignore | |
|
||||||
<kbd>S</kbd>: View stash options
|
| `` r `` | ファイルをリフレッシュ | |
|
||||||
<kbd>a</kbd>: すべての変更をステージ/アンステージ
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
|
| `` S `` | View stash options | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: View upstream reset options
|
| `` a `` | すべての変更をステージ/アンステージ | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: View reset options
|
| `` <enter> `` | Stage lines / Collapse directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: Git mergetoolを開く
|
| `` g `` | View upstream reset options | |
|
||||||
<kbd>f</kbd>: Fetch
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||||
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## ブランチ
|
## ブランチ
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: ブランチ名をクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Show git-flow options
|
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||||
<kbd><space></kbd>: チェックアウト
|
| `` i `` | Show git-flow options | |
|
||||||
<kbd>n</kbd>: 新しいブランチを作成
|
| `` <space> `` | チェックアウト | Checkout selected item. |
|
||||||
<kbd>o</kbd>: Pull Requestを作成
|
| `` n `` | 新しいブランチを作成 | |
|
||||||
<kbd>O</kbd>: Create pull request options
|
| `` o `` | Pull Requestを作成 | |
|
||||||
<kbd><c-y></kbd>: Pull RequestのURLをクリップボードにコピー
|
| `` O `` | View create pull request options | |
|
||||||
<kbd>c</kbd>: Checkout by name
|
| `` <c-y> `` | Pull RequestのURLをクリップボードにコピー | |
|
||||||
<kbd>F</kbd>: Force checkout
|
| `` c `` | Checkout by name | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: ブランチを削除
|
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: 現在のブランチにマージ
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: Fast-forward this branch from its upstream
|
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: タグを作成
|
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` T `` | タグを作成 | |
|
||||||
<kbd>R</kbd>: ブランチ名を変更
|
| `` s `` | 並び替え | |
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
| `` g `` | Reset | |
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
| `` R `` | ブランチ名を変更 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## メインパネル (Merging)
|
## メインパネル (Merging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: ファイルを編集
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: ファイルを開く
|
| `` <space> `` | Pick hunk | |
|
||||||
<kbd><left></kbd>: 前のコンフリクトを選択
|
| `` b `` | Pick all hunks | |
|
||||||
<kbd><right></kbd>: 次のコンフリクトを選択
|
| `` <up> `` | 前のhunkを選択 | |
|
||||||
<kbd><up></kbd>: 前のhunkを選択
|
| `` <down> `` | 次のhunkを選択 | |
|
||||||
<kbd><down></kbd>: 次のhunkを選択
|
| `` <left> `` | 前のコンフリクトを選択 | |
|
||||||
<kbd>z</kbd>: アンドゥ
|
| `` <right> `` | 次のコンフリクトを選択 | |
|
||||||
<kbd>M</kbd>: Git mergetoolを開く
|
| `` z `` | アンドゥ | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: Pick hunk
|
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||||
<kbd>b</kbd>: Pick all hunks
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
<kbd><esc></kbd>: ファイル一覧に戻る
|
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | ファイル一覧に戻る | |
|
||||||
|
|
||||||
## メインパネル (Normal)
|
## メインパネル (Normal)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: 下にスクロール (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: 上にスクロール (fn+down)
|
| `` mouse wheel down (fn+up) `` | 下にスクロール | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | 上にスクロール | |
|
||||||
|
|
||||||
## メインパネル (Patch Building)
|
## メインパネル (Patch Building)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 前のhunkを選択
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 次のhunkを選択
|
| `` <left> `` | 前のhunkを選択 | |
|
||||||
<kbd>v</kbd>: 範囲選択を切り替え
|
| `` <right> `` | 次のhunkを選択 | |
|
||||||
<kbd>V</kbd>: 範囲選択を切り替え
|
| `` v `` | 範囲選択を切り替え | |
|
||||||
<kbd>a</kbd>: Hunk選択を切り替え
|
| `` a `` | Hunk選択を切り替え | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 選択されたテキストをクリップボードにコピー
|
| `` <c-o> `` | 選択されたテキストをクリップボードにコピー | |
|
||||||
<kbd>o</kbd>: ファイルを開く
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
<kbd>e</kbd>: ファイルを編集
|
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 行をパッチに追加/削除
|
| `` <space> `` | 行をパッチに追加/削除 | |
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
| `` <esc> `` | Exit custom patch builder | |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` / `` | 検索を開始 | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## メインパネル (Staging)
|
## メインパネル (Staging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 前のhunkを選択
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 次のhunkを選択
|
| `` <left> `` | 前のhunkを選択 | |
|
||||||
<kbd>v</kbd>: 範囲選択を切り替え
|
| `` <right> `` | 次のhunkを選択 | |
|
||||||
<kbd>V</kbd>: 範囲選択を切り替え
|
| `` v `` | 範囲選択を切り替え | |
|
||||||
<kbd>a</kbd>: Hunk選択を切り替え
|
| `` a `` | Hunk選択を切り替え | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 選択されたテキストをクリップボードにコピー
|
| `` <c-o> `` | 選択されたテキストをクリップボードにコピー | |
|
||||||
<kbd>o</kbd>: ファイルを開く
|
| `` <space> `` | ステージ/アンステージ | 選択行をステージ/アンステージ |
|
||||||
<kbd>e</kbd>: ファイルを編集
|
| `` d `` | 変更を削除 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: ファイル一覧に戻る
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
<kbd><tab></kbd>: パネルを切り替え
|
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 選択行をステージ/アンステージ
|
| `` <esc> `` | ファイル一覧に戻る | |
|
||||||
<kbd>d</kbd>: 変更を削除 (git reset)
|
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Edit hunk
|
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: 変更をコミット
|
| `` c `` | 変更をコミット | Commit staged changes. |
|
||||||
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
|
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
||||||
<kbd>C</kbd>: gitエディタを使用して変更をコミット
|
| `` C `` | gitエディタを使用して変更をコミット | |
|
||||||
<kbd>/</kbd>: 検索を開始
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## メニュー
|
## メニュー
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 実行
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 閉じる
|
| `` <enter> `` | 実行 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | 閉じる | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## リモート
|
## リモート
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: リモートをfetch
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: リモートを新規追加
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: リモートを削除
|
| `` n `` | リモートを新規追加 | |
|
||||||
<kbd>e</kbd>: リモートを編集
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | リモートを編集 |
|
||||||
</pre>
|
| `` f `` | Fetch | リモートをfetch |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## リモートブランチ
|
## リモートブランチ
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: ブランチ名をクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: チェックアウト
|
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||||
<kbd>n</kbd>: 新しいブランチを作成
|
| `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: 現在のブランチにマージ
|
| `` n `` | 新しいブランチを作成 | |
|
||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: ブランチを削除
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
| `` s `` | 並び替え | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 参照ログ
|
## 参照ログ
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: コミットのSHAをクリップボードにコピー
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: コミットをチェックアウト
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
<kbd>y</kbd>: コミットの情報をコピー
|
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: ブラウザでコミットを開く
|
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: コミットにブランチを作成
|
| `` o `` | ブラウザでコミットを開く | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | コミットにブランチを作成 | |
|
||||||
<kbd>c</kbd>: コミットをコピー (cherry-pick)
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 確認パネル
|
## 確認パネル
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 確認
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 閉じる/キャンセル
|
| `` <enter> `` | 確認 | |
|
||||||
</pre>
|
| `` <esc> `` | 閉じる/キャンセル | |
|
||||||
|
|||||||
+302
-266
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit 키 바인딩
|
# Lazygit 키 바인딩
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
## 글로벌 키 바인딩
|
## 글로벌 키 바인딩
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: 최근에 사용한 저장소로 전환
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: 메인 패널을 위로 스크롤 (fn+up/shift+k)
|
| `` <c-r> `` | 최근에 사용한 저장소로 전환 | |
|
||||||
<kbd><pgdown></kbd>: 메인 패널을 아래로로 스크롤 (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | 메인 패널을 위로 스크롤 | |
|
||||||
<kbd>@</kbd>: 명령어 로그 메뉴 열기
|
| `` <pgdown> (fn+down/shift+j) `` | 메인 패널을 아래로로 스크롤 | |
|
||||||
<kbd>}</kbd>: Diff 보기의 변경 사항 주위에 표시되는 컨텍스트의 크기를 늘리기
|
| `` @ `` | 명령어 로그 메뉴 열기 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: Diff 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기
|
| `` P `` | 푸시 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: Execute custom command
|
| `` p `` | 업데이트 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: 커스텀 Patch 옵션 보기
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: View merge/rebase options
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: 새로고침
|
| `` } `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트의 크기를 늘리기 | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: 다음 스크린 모드 (normal/half/fullscreen)
|
| `` { `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기 | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: 이전 스크린 모드
|
| `` : `` | Execute custom command | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: 매뉴 열기
|
| `` <c-p> `` | 커스텀 Patch 옵션 보기 | |
|
||||||
<kbd><c-s></kbd>: View filter-by-path options
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: Diff 메뉴 열기
|
| `` R `` | 새로고침 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: Diff 메뉴 열기
|
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
|
||||||
<kbd><c-w></kbd>: 공백문자를 Diff 뷰에서 표시 여부 전환
|
| `` _ `` | 이전 스크린 모드 | |
|
||||||
<kbd>z</kbd>: 되돌리기 (reflog) (실험적)
|
| `` ? `` | 매뉴 열기 | |
|
||||||
<kbd><c-z></kbd>: 다시 실행 (reflog) (실험적)
|
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: 푸시
|
| `` W `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: 업데이트
|
| `` <c-e> `` | Diff 메뉴 열기 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | 종료 | |
|
||||||
|
| `` <esc> `` | 취소 | |
|
||||||
|
| `` <c-w> `` | 공백문자를 Diff 뷰에서 표시 여부 전환 | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | 되돌리기 (reflog) (실험적) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
| `` <c-z> `` | 다시 실행 (reflog) (실험적) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
|
||||||
## List panel navigation
|
## List panel navigation
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: 이전 페이지
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: 다음 페이지
|
| `` , `` | 이전 페이지 | |
|
||||||
<kbd><</kbd>: 맨 위로 스크롤
|
| `` . `` | 다음 페이지 | |
|
||||||
<kbd>></kbd>: 맨 아래로 스크롤
|
| `` < `` | 맨 위로 스크롤 | |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` > `` | 맨 아래로 스크롤 | |
|
||||||
<kbd>H</kbd>: 우 스크롤
|
| `` v `` | 드래그 선택 전환 | |
|
||||||
<kbd>L</kbd>: 좌 스크롤
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: 이전 탭
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: 다음 탭
|
| `` / `` | 검색 시작 | |
|
||||||
</pre>
|
| `` H `` | 우 스크롤 | |
|
||||||
|
| `` L `` | 좌 스크롤 | |
|
||||||
|
| `` ] `` | 이전 탭 | |
|
||||||
|
| `` [ `` | 다음 탭 | |
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 커밋 SHA를 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 커밋을 체크아웃
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
<kbd>y</kbd>: 커밋 attribute 복사
|
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: 브라우저에서 커밋 열기
|
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
|
| `` o `` | 브라우저에서 커밋 열기 | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
|
||||||
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
|
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 적용
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Pop
|
| `` <space> `` | 적용 | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: Drop
|
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: 새 브랜치 생성
|
| `` d `` | Drop | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Rename stash
|
| `` n `` | 새 브랜치 생성 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` r `` | Rename stash | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | View selected item's files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 커밋 SHA를 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 커밋을 체크아웃
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
<kbd>y</kbd>: 커밋 attribute 복사
|
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: 브라우저에서 커밋 열기
|
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
|
| `` o `` | 브라우저에서 커밋 열기 | |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
|
||||||
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
|
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` <enter> `` | View selected item's files | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 메뉴
|
## 메뉴
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 실행
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 닫기
|
| `` <enter> `` | 실행 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | 닫기 | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 메인 패널 (Merging)
|
## 메인 패널 (Merging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: 파일 편집
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: 파일 닫기
|
| `` <space> `` | Pick hunk | |
|
||||||
<kbd><left></kbd>: 이전 충돌을 선택
|
| `` b `` | Pick all hunks | |
|
||||||
<kbd><right></kbd>: 다음 충돌을 선택
|
| `` <up> `` | 이전 hunk를 선택 | |
|
||||||
<kbd><up></kbd>: 이전 hunk를 선택
|
| `` <down> `` | 다음 hunk를 선택 | |
|
||||||
<kbd><down></kbd>: 다음 hunk를 선택
|
| `` <left> `` | 이전 충돌을 선택 | |
|
||||||
<kbd>z</kbd>: 되돌리기
|
| `` <right> `` | 다음 충돌을 선택 | |
|
||||||
<kbd>M</kbd>: Git mergetool를 열기
|
| `` z `` | 되돌리기 | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: Pick hunk
|
| `` e `` | 파일 편집 | Open file in external editor. |
|
||||||
<kbd>b</kbd>: Pick all hunks
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
<kbd><esc></kbd>: 파일 목록으로 돌아가기
|
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | 파일 목록으로 돌아가기 | |
|
||||||
|
|
||||||
## 메인 패널 (Normal)
|
## 메인 패널 (Normal)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: 아래로 스크롤 (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: 위로 스크롤 (fn+down)
|
| `` mouse wheel down (fn+up) `` | 아래로 스크롤 | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | 위로 스크롤 | |
|
||||||
|
|
||||||
## 메인 패널 (Patch Building)
|
## 메인 패널 (Patch Building)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 이전 hunk를 선택
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 다음 hunk를 선택
|
| `` <left> `` | 이전 hunk를 선택 | |
|
||||||
<kbd>v</kbd>: 드래그 선택 전환
|
| `` <right> `` | 다음 hunk를 선택 | |
|
||||||
<kbd>V</kbd>: 드래그 선택 전환
|
| `` v `` | 드래그 선택 전환 | |
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
| `` a `` | Toggle select hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 선택한 텍스트를 클립보드에 복사
|
| `` <c-o> `` | 선택한 텍스트를 클립보드에 복사 | |
|
||||||
<kbd>o</kbd>: 파일 닫기
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
<kbd>e</kbd>: 파일 편집
|
| `` e `` | 파일 편집 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Line(s)을 패치에 추가/삭제
|
| `` <space> `` | Line(s)을 패치에 추가/삭제 | |
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
| `` <esc> `` | Exit custom patch builder | |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` / `` | 검색 시작 | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 메인 패널 (Staging)
|
## 메인 패널 (Staging)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 이전 hunk를 선택
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 다음 hunk를 선택
|
| `` <left> `` | 이전 hunk를 선택 | |
|
||||||
<kbd>v</kbd>: 드래그 선택 전환
|
| `` <right> `` | 다음 hunk를 선택 | |
|
||||||
<kbd>V</kbd>: 드래그 선택 전환
|
| `` v `` | 드래그 선택 전환 | |
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
| `` a `` | Toggle select hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 선택한 텍스트를 클립보드에 복사
|
| `` <c-o> `` | 선택한 텍스트를 클립보드에 복사 | |
|
||||||
<kbd>o</kbd>: 파일 닫기
|
| `` <space> `` | Staged 전환 | 선택한 행을 staged / unstaged |
|
||||||
<kbd>e</kbd>: 파일 편집
|
| `` d `` | 변경을 삭제 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: 파일 목록으로 돌아가기
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
<kbd><tab></kbd>: 패널 전환
|
| `` e `` | 파일 편집 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 선택한 행을 staged / unstaged
|
| `` <esc> `` | 파일 목록으로 돌아가기 | |
|
||||||
<kbd>d</kbd>: 변경을 삭제 (git reset)
|
| `` <tab> `` | 패널 전환 | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Edit hunk
|
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: 커밋 변경내용
|
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
|
| `` C `` | Git 편집기를 사용하여 변경 내용을 커밋합니다. | |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 브랜치
|
## 브랜치
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 브랜치명을 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Git-flow 옵션 보기
|
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
|
||||||
<kbd><space></kbd>: 체크아웃
|
| `` i `` | Git-flow 옵션 보기 | |
|
||||||
<kbd>n</kbd>: 새 브랜치 생성
|
| `` <space> `` | 체크아웃 | Checkout selected item. |
|
||||||
<kbd>o</kbd>: 풀 리퀘스트 생성
|
| `` n `` | 새 브랜치 생성 | |
|
||||||
<kbd>O</kbd>: 풀 리퀘스트 생성 옵션
|
| `` o `` | 풀 리퀘스트 생성 | |
|
||||||
<kbd><c-y></kbd>: 풀 리퀘스트 URL을 클립보드에 복사
|
| `` O `` | 풀 리퀘스트 생성 옵션 | |
|
||||||
<kbd>c</kbd>: 이름으로 체크아웃
|
| `` <c-y> `` | 풀 리퀘스트 URL을 클립보드에 복사 | |
|
||||||
<kbd>F</kbd>: 강제 체크아웃
|
| `` c `` | 이름으로 체크아웃 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: 브랜치 삭제
|
| `` F `` | 강제 체크아웃 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: 현재 브랜치에 병합
|
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: Fast-forward this branch from its upstream
|
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: 태그를 생성
|
| `` f `` | Fast-forward this branch from its upstream | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` T `` | 태그를 생성 | |
|
||||||
<kbd>R</kbd>: 브랜치 이름 변경
|
| `` s `` | Sort order | |
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
| `` g `` | View reset options | |
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
| `` R `` | 브랜치 이름 변경 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 상태
|
## 상태
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: 설정 파일 열기
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: 설정 파일 수정
|
| `` o `` | 설정 파일 열기 | Open file in default application. |
|
||||||
<kbd>u</kbd>: 업데이트 확인
|
| `` e `` | 설정 파일 수정 | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: 최근에 사용한 저장소로 전환
|
| `` u `` | 업데이트 확인 | |
|
||||||
<kbd>a</kbd>: 모든 브랜치 로그 표시
|
| `` <enter> `` | 최근에 사용한 저장소로 전환 | |
|
||||||
</pre>
|
| `` a `` | 모든 브랜치 로그 표시 | |
|
||||||
|
|
||||||
## 서브모듈
|
## 서브모듈
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 서브모듈 이름을 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: 서브모듈 열기
|
| `` <c-o> `` | 서브모듈 이름을 클립보드에 복사 | |
|
||||||
<kbd>d</kbd>: 서브모듈 삭제
|
| `` <enter> `` | Enter | 서브모듈 열기 |
|
||||||
<kbd>u</kbd>: 서브모듈 업데이트
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: 새로운 서브모듈 추가
|
| `` u `` | Update | 서브모듈 업데이트 |
|
||||||
<kbd>e</kbd>: 서브모듈의 URL을 수정
|
| `` n `` | 새로운 서브모듈 추가 | |
|
||||||
<kbd>i</kbd>: 서브모듈 초기화
|
| `` e `` | 서브모듈의 URL을 수정 | |
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
| `` i `` | Initialize | 서브모듈 초기화 |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | View bulk submodule options | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 원격
|
## 원격
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: 원격을 업데이트
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: 새로운 Remote 추가
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: Remote를 삭제
|
| `` n `` | 새로운 Remote 추가 | |
|
||||||
<kbd>e</kbd>: Remote를 수정
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | Remote를 수정 |
|
||||||
</pre>
|
| `` f `` | Fetch | 원격을 업데이트 |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 원격 브랜치
|
## 원격 브랜치
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 브랜치명을 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 체크아웃
|
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
|
||||||
<kbd>n</kbd>: 새 브랜치 생성
|
| `` <space> `` | 체크아웃 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: 현재 브랜치에 병합
|
| `` n `` | 새 브랜치 생성 | |
|
||||||
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
|
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: 브랜치 삭제
|
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
| `` s `` | Sort order | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 커밋
|
## 커밋
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 커밋 SHA를 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
<kbd>b</kbd>: Bisect 옵션 보기
|
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
|
||||||
<kbd>s</kbd>: Squash down
|
| `` b `` | Bisect 옵션 보기 | |
|
||||||
<kbd>f</kbd>: Fixup commit
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: 커밋메시지 변경
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: 에디터에서 커밋메시지 수정
|
| `` r `` | 커밋메시지 변경 | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: 커밋 삭제
|
| `` R `` | 에디터에서 커밋메시지 수정 | |
|
||||||
<kbd>e</kbd>: 커밋을 편집
|
| `` d `` | 커밋 삭제 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: Pick commit (when mid-rebase)
|
| `` e `` | Edit (start interactive rebase) | 커밋을 편집 |
|
||||||
<kbd>F</kbd>: Create fixup commit for this commit
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: 커밋을 1개 아래로 이동
|
| `` p `` | Pick | Pick commit (when mid-rebase) |
|
||||||
<kbd><c-k></kbd>: 커밋을 1개 위로 이동
|
| `` F `` | Create fixup commit | Create fixup commit for this commit |
|
||||||
<kbd>v</kbd>: 커밋을 붙여넣기 (cherry-pick)
|
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits above selected commit (autosquash) |
|
||||||
<kbd>A</kbd>: Amend commit with staged changes
|
| `` <c-j> `` | 커밋을 1개 아래로 이동 | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | 커밋을 1개 위로 이동 | |
|
||||||
<kbd>t</kbd>: 커밋 되돌리기
|
| `` V `` | 커밋을 붙여넣기 (cherry-pick) | |
|
||||||
<kbd>T</kbd>: Tag commit
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: 로그 메뉴 열기
|
| `` A `` | Amend | Amend commit with staged changes |
|
||||||
<kbd><space></kbd>: 커밋을 체크아웃
|
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: 커밋 attribute 복사
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: 브라우저에서 커밋 열기
|
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
|
| `` <c-l> `` | 로그 메뉴 열기 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
|
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
| `` o `` | 브라우저에서 커밋 열기 | |
|
||||||
<kbd><enter></kbd>: View selected item's files
|
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | View selected item's files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 커밋 파일
|
## 커밋 파일
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 커밋한 파일명을 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Checkout file
|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
||||||
<kbd>d</kbd>: Discard this commit's changes to this file
|
| `` c `` | 체크아웃 | Checkout file |
|
||||||
<kbd>o</kbd>: 파일 닫기
|
| `` d `` | Remove | Discard this commit's changes to this file |
|
||||||
<kbd>e</kbd>: 파일 편집
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
<kbd><space></kbd>: Toggle file included in patch
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
| `` <space> `` | Toggle file included in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: 파일 트리뷰로 전환
|
| `` a `` | Toggle all files included in patch | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` <enter> `` | Enter file to add selected lines to the patch (or toggle directory collapsed) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 커밋메시지
|
## 커밋메시지
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 확인
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 닫기
|
| `` <enter> `` | 확인 | |
|
||||||
</pre>
|
| `` <esc> `` | 닫기 | |
|
||||||
|
|
||||||
## 태그
|
## 태그
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 체크아웃
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: 태그 삭제
|
| `` <space> `` | 체크아웃 | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: 태그를 push
|
| `` n `` | 태그를 생성 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 태그를 생성
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: View reset options
|
| `` P `` | 태그를 push | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 파일
|
## 파일
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 파일명을 클립보드에 복사
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: View 'discard changes' options
|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
||||||
<kbd><space></kbd>: Staged 전환
|
| `` <space> `` | Staged 전환 | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: 파일을 필터하기 (Staged/unstaged)
|
| `` <c-b> `` | 파일을 필터하기 (Staged/unstaged) | |
|
||||||
<kbd>c</kbd>: 커밋 변경내용
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
||||||
<kbd>A</kbd>: 마지맛 커밋 수정
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
|
| `` A `` | 마지맛 커밋 수정 | |
|
||||||
<kbd>e</kbd>: 파일 편집
|
| `` C `` | Git 편집기를 사용하여 변경 내용을 커밋합니다. | |
|
||||||
<kbd>o</kbd>: 파일 닫기
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: Ignore file
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: 파일 새로고침
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
<kbd>s</kbd>: 변경사항을 Stash
|
| `` i `` | Ignore file | |
|
||||||
<kbd>S</kbd>: Stash 옵션 보기
|
| `` r `` | 파일 새로고침 | |
|
||||||
<kbd>a</kbd>: 모든 변경을 Staged/unstaged으로 전환
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
|
| `` S `` | Stash 옵션 보기 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: View upstream reset options
|
| `` a `` | 모든 변경을 Staged/unstaged으로 전환 | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: View reset options
|
| `` <enter> `` | Stage individual hunks/lines for file, or collapse/expand for directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: 파일 트리뷰로 전환
|
| `` d `` | View 'discard changes' options | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: Git mergetool를 열기
|
| `` g `` | View upstream reset options | |
|
||||||
<kbd>f</kbd>: Fetch
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: 검색 시작
|
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
||||||
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 확인 패널
|
## 확인 패널
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 확인
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 닫기/취소
|
| `` <enter> `` | 확인 | |
|
||||||
</pre>
|
| `` <esc> `` | 닫기/취소 | |
|
||||||
|
|||||||
+302
-266
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit Sneltoetsen
|
# Lazygit Sneltoetsen
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
## Globale sneltoetsen
|
## Globale sneltoetsen
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: Wissel naar een recente repo
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: Scroll naar beneden vanaf hoofdpaneel (fn+up/shift+k)
|
| `` <c-r> `` | Wissel naar een recente repo | |
|
||||||
<kbd><pgdown></kbd>: Scroll naar beneden vanaf hoofdpaneel (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | Scroll naar beneden vanaf hoofdpaneel | |
|
||||||
<kbd>@</kbd>: Open command log menu
|
| `` <pgdown> (fn+down/shift+j) `` | Scroll naar beneden vanaf hoofdpaneel | |
|
||||||
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
|
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: Voer aangepaste commando uit
|
| `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: Bekijk aangepaste patch opties
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: Bekijk merge/rebase opties
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: Verversen
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: Volgende scherm modus (normaal/half/groot)
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: Vorige scherm modus
|
| `` : `` | Voer aangepaste commando uit | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: Open menu
|
| `` <c-p> `` | Bekijk aangepaste patch opties | |
|
||||||
<kbd><c-s></kbd>: Bekijk scoping opties
|
| `` m `` | Bekijk merge/rebase opties | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: Open diff menu
|
| `` R `` | Verversen | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: Open diff menu
|
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
|
||||||
<kbd><c-w></kbd>: Toggle whether or not whitespace changes are shown in the diff view
|
| `` _ `` | Vorige scherm modus | |
|
||||||
<kbd>z</kbd>: Ongedaan maken (via reflog) (experimenteel)
|
| `` ? `` | Open menu | |
|
||||||
<kbd><c-z></kbd>: Redo (via reflog) (experimenteel)
|
| `` <c-s> `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: Push
|
| `` W `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: Pull
|
| `` <c-e> `` | Open diff menu | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | Quit | |
|
||||||
|
| `` <esc> `` | Annuleren | |
|
||||||
|
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | Ongedaan maken (via reflog) (experimenteel) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
| `` <c-z> `` | Redo (via reflog) (experimenteel) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
|
||||||
## Lijstpaneel navigatie
|
## Lijstpaneel navigatie
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: Vorige pagina
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: Volgende pagina
|
| `` , `` | Vorige pagina | |
|
||||||
<kbd><</kbd>: Scroll naar boven
|
| `` . `` | Volgende pagina | |
|
||||||
<kbd>></kbd>: Scroll naar beneden
|
| `` < `` | Scroll naar boven | |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` > `` | Scroll naar beneden | |
|
||||||
<kbd>H</kbd>: Scroll left
|
| `` v `` | Toggle drag selecteer | |
|
||||||
<kbd>L</kbd>: Scroll right
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: Volgende tabblad
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: Vorige tabblad
|
| `` / `` | Start met zoeken | |
|
||||||
</pre>
|
| `` H `` | Scroll left | |
|
||||||
|
| `` L `` | Scroll right | |
|
||||||
|
| `` ] `` | Volgende tabblad | |
|
||||||
|
| `` [ `` | Vorige tabblad | |
|
||||||
|
|
||||||
## Bestanden
|
## Bestanden
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer de bestandsnaam naar het klembord
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Bekijk 'veranderingen ongedaan maken' opties
|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
|
||||||
<kbd><space></kbd>: Toggle staged
|
| `` <space> `` | Toggle staged | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: Filter files by status
|
| `` <c-b> `` | Filter files by status | |
|
||||||
<kbd>c</kbd>: Commit veranderingen
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
| `` c `` | Commit veranderingen | Commit staged changes. |
|
||||||
<kbd>A</kbd>: Wijzig laatste commit
|
| `` w `` | Commit veranderingen zonder pre-commit hook | |
|
||||||
<kbd>C</kbd>: Commit veranderingen met de git editor
|
| `` A `` | Wijzig laatste commit | |
|
||||||
<kbd>e</kbd>: Verander bestand
|
| `` C `` | Commit veranderingen met de git editor | |
|
||||||
<kbd>o</kbd>: Open bestand
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: Ignore or exclude file
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: Refresh bestanden
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
<kbd>s</kbd>: Stash-bestanden
|
| `` i `` | Ignore or exclude file | |
|
||||||
<kbd>S</kbd>: Bekijk stash opties
|
| `` r `` | Refresh bestanden | |
|
||||||
<kbd>a</kbd>: Toggle staged alle
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: Stage individuele hunks/lijnen
|
| `` S `` | Bekijk stash opties | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: Bekijk upstream reset opties
|
| `` a `` | Toggle staged alle | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: Bekijk reset opties
|
| `` <enter> `` | Stage individuele hunks/lijnen | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: Toggle bestandsboom weergave
|
| `` d `` | Bekijk 'veranderingen ongedaan maken' opties | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
| `` g `` | Bekijk upstream reset opties | |
|
||||||
<kbd>f</kbd>: Fetch
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` ` `` | Toggle bestandsboom weergave | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Bevestigingspaneel
|
## Bevestigingspaneel
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Bevestig
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Sluiten
|
| `` <enter> `` | Bevestig | |
|
||||||
</pre>
|
| `` <esc> `` | Sluiten | |
|
||||||
|
|
||||||
## Branches
|
## Branches
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer branch name naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Laat git-flow opties zien
|
| `` <c-o> `` | Kopieer branch name naar klembord | |
|
||||||
<kbd><space></kbd>: Uitchecken
|
| `` i `` | Laat git-flow opties zien | |
|
||||||
<kbd>n</kbd>: Nieuwe branch
|
| `` <space> `` | Uitchecken | Checkout selected item. |
|
||||||
<kbd>o</kbd>: Maak een pull-request
|
| `` n `` | Nieuwe branch | |
|
||||||
<kbd>O</kbd>: Bekijk opties voor pull-aanvraag
|
| `` o `` | Maak een pull-request | |
|
||||||
<kbd><c-y></kbd>: Kopieer de URL van het pull-verzoek naar het klembord
|
| `` O `` | Bekijk opties voor pull-aanvraag | |
|
||||||
<kbd>c</kbd>: Uitchecken bij naam
|
| `` <c-y> `` | Kopieer de URL van het pull-verzoek naar het klembord | |
|
||||||
<kbd>F</kbd>: Forceer checkout
|
| `` c `` | Uitchecken bij naam | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: Verwijder branch
|
| `` F `` | Forceer checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: Rebase branch
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: Merge in met huidige checked out branch
|
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: Fast-forward deze branch vanaf zijn upstream
|
| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: Creëer tag
|
| `` f `` | Fast-forward deze branch vanaf zijn upstream | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` T `` | Creëer tag | |
|
||||||
<kbd>R</kbd>: Hernoem branch
|
| `` s `` | Sort order | |
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
| `` g `` | Bekijk reset opties | |
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
| `` R `` | Hernoem branch | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Bekijk commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Commit bericht
|
## Commit bericht
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Bevestig
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Sluiten
|
| `` <enter> `` | Bevestig | |
|
||||||
</pre>
|
| `` <esc> `` | Sluiten | |
|
||||||
|
|
||||||
## Commit bestanden
|
## Commit bestanden
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer de vastgelegde bestandsnaam naar het klembord
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Bestand uitchecken
|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
|
||||||
<kbd>d</kbd>: Uitsluit deze commit zijn veranderingen aan dit bestand
|
| `` c `` | Uitchecken | Bestand uitchecken |
|
||||||
<kbd>o</kbd>: Open bestand
|
| `` d `` | Remove | Uitsluit deze commit zijn veranderingen aan dit bestand |
|
||||||
<kbd>e</kbd>: Verander bestand
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
<kbd><space></kbd>: Toggle bestand inbegrepen in patch
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: Enter bestand om geselecteerde regels toe te voegen aan de patch
|
| `` <space> `` | Toggle bestand inbegrepen in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: Toggle bestandsboom weergave
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` <enter> `` | Enter bestand om geselecteerde regels toe te voegen aan de patch | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | Toggle bestandsboom weergave | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer commit SHA naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
<kbd>b</kbd>: View bisect options
|
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
|
||||||
<kbd>s</kbd>: Squash beneden
|
| `` b `` | View bisect options | |
|
||||||
<kbd>f</kbd>: Fixup commit
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: Hernoem commit
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: Hernoem commit met editor
|
| `` r `` | Hernoem commit | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: Verwijder commit
|
| `` R `` | Hernoem commit met editor | |
|
||||||
<kbd>e</kbd>: Wijzig commit
|
| `` d `` | Verwijder commit | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: Kies commit (wanneer midden in rebase)
|
| `` e `` | Edit (start interactive rebase) | Wijzig commit |
|
||||||
<kbd>F</kbd>: Creëer fixup commit
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: Squash bovenstaande commits
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: Verplaats commit 1 naar beneden
|
| `` p `` | Pick | Kies commit (wanneer midden in rebase) |
|
||||||
<kbd><c-k></kbd>: Verplaats commit 1 naar boven
|
| `` F `` | Creëer fixup commit | Creëer fixup commit |
|
||||||
<kbd>v</kbd>: Plak commits (cherry-pick)
|
| `` S `` | Apply fixup commits | Squash bovenstaande commits |
|
||||||
<kbd>A</kbd>: Wijzig commit met staged veranderingen
|
| `` <c-j> `` | Verplaats commit 1 naar beneden | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | Verplaats commit 1 naar boven | |
|
||||||
<kbd>t</kbd>: Commit ongedaan maken
|
| `` V `` | Plak commits (cherry-pick) | |
|
||||||
<kbd>T</kbd>: Tag commit
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: Open log menu
|
| `` A `` | Amend | Wijzig commit met staged veranderingen |
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Creëer nieuwe branch van commit
|
| `` <c-l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: Kopieer commit (cherry-pick)
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
| `` n `` | Creëer nieuwe branch van commit | |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Bekijk gecommite bestanden | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Uitvoeren
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Sluiten
|
| `` <enter> `` | Uitvoeren | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | Sluiten | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Mergen
|
## Mergen
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: Verander bestand
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: Open bestand
|
| `` <space> `` | Kies stuk | |
|
||||||
<kbd><left></kbd>: Selecteer voorgaand conflict
|
| `` b `` | Kies beide stukken | |
|
||||||
<kbd><right></kbd>: Selecteer volgende conflict
|
| `` <up> `` | Selecteer bovenste hunk | |
|
||||||
<kbd><up></kbd>: Selecteer bovenste hunk
|
| `` <down> `` | Selecteer onderste hunk | |
|
||||||
<kbd><down></kbd>: Selecteer onderste hunk
|
| `` <left> `` | Selecteer voorgaand conflict | |
|
||||||
<kbd>z</kbd>: Ongedaan maken
|
| `` <right> `` | Selecteer volgende conflict | |
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
| `` z `` | Ongedaan maken | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: Kies stuk
|
| `` e `` | Verander bestand | Open file in external editor. |
|
||||||
<kbd>b</kbd>: Kies beide stukken
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
<kbd><esc></kbd>: Ga terug naar het bestanden paneel
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | Ga terug naar het bestanden paneel | |
|
||||||
|
|
||||||
## Normaal
|
## Normaal
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: Scroll omlaag (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: Scroll omhoog (fn+down)
|
| `` mouse wheel down (fn+up) `` | Scroll omlaag | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | Scroll omhoog | |
|
||||||
|
|
||||||
## Patch bouwen
|
## Patch bouwen
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Selecteer de vorige hunk
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Selecteer de volgende hunk
|
| `` <left> `` | Selecteer de vorige hunk | |
|
||||||
<kbd>v</kbd>: Toggle drag selecteer
|
| `` <right> `` | Selecteer de volgende hunk | |
|
||||||
<kbd>V</kbd>: Toggle drag selecteer
|
| `` v `` | Toggle drag selecteer | |
|
||||||
<kbd>a</kbd>: Toggle selecteer hunk
|
| `` a `` | Toggle selecteer hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
<kbd>o</kbd>: Open bestand
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
<kbd>e</kbd>: Verander bestand
|
| `` e `` | Verander bestand | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Voeg toe/verwijder lijn(en) in patch
|
| `` <space> `` | Voeg toe/verwijder lijn(en) in patch | |
|
||||||
<kbd><esc></kbd>: Sluit lijn-bij-lijn modus
|
| `` <esc> `` | Sluit lijn-bij-lijn modus | |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` / `` | Start met zoeken | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer commit SHA naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Creëer nieuwe branch van commit
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` n `` | Creëer nieuwe branch van commit | |
|
||||||
<kbd>c</kbd>: Kopieer commit (cherry-pick)
|
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Bekijk commits | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Remote branches
|
## Remote branches
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer branch name naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Uitchecken
|
| `` <c-o> `` | Kopieer branch name naar klembord | |
|
||||||
<kbd>n</kbd>: Nieuwe branch
|
| `` <space> `` | Uitchecken | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: Merge in met huidige checked out branch
|
| `` n `` | Nieuwe branch | |
|
||||||
<kbd>r</kbd>: Rebase branch
|
| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: Verwijder branch
|
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: Stel in als upstream van uitgecheckte branch
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` u `` | Set as upstream | Stel in als upstream van uitgecheckte branch |
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
| `` s `` | Sort order | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Bekijk commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Remotes
|
## Remotes
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: Fetch remote
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: Voeg een nieuwe remote toe
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: Verwijder remote
|
| `` n `` | Voeg een nieuwe remote toe | |
|
||||||
<kbd>e</kbd>: Wijzig remote
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | Wijzig remote |
|
||||||
</pre>
|
| `` f `` | Fetch | Fetch remote |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Staging
|
## Staging
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Selecteer de vorige hunk
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Selecteer de volgende hunk
|
| `` <left> `` | Selecteer de vorige hunk | |
|
||||||
<kbd>v</kbd>: Toggle drag selecteer
|
| `` <right> `` | Selecteer de volgende hunk | |
|
||||||
<kbd>V</kbd>: Toggle drag selecteer
|
| `` v `` | Toggle drag selecteer | |
|
||||||
<kbd>a</kbd>: Toggle selecteer hunk
|
| `` a `` | Toggle selecteer hunk | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
<kbd>o</kbd>: Open bestand
|
| `` <space> `` | Toggle staged | Toggle lijnen staged / unstaged |
|
||||||
<kbd>e</kbd>: Verander bestand
|
| `` d `` | Verwijdert change (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: Ga terug naar het bestanden paneel
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
<kbd><tab></kbd>: Ga naar een ander paneel
|
| `` e `` | Verander bestand | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Toggle lijnen staged / unstaged
|
| `` <esc> `` | Ga terug naar het bestanden paneel | |
|
||||||
<kbd>d</kbd>: Verwijdert change (git reset)
|
| `` <tab> `` | Ga naar een ander paneel | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Edit hunk
|
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: Commit veranderingen
|
| `` c `` | Commit veranderingen | Commit staged changes. |
|
||||||
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
| `` w `` | Commit veranderingen zonder pre-commit hook | |
|
||||||
<kbd>C</kbd>: Commit veranderingen met de git editor
|
| `` C `` | Commit veranderingen met de git editor | |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Toepassen
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Pop
|
| `` <space> `` | Toepassen | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: Laten vallen
|
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: Nieuwe branch
|
| `` d `` | Laten vallen | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Rename stash
|
| `` n `` | Nieuwe branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
| `` r `` | Rename stash | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Bekijk gecommite bestanden | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: Open config bestand
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: Verander config bestand
|
| `` o `` | Open config bestand | Open file in default application. |
|
||||||
<kbd>u</kbd>: Check voor updates
|
| `` e `` | Verander config bestand | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: Wissel naar een recente repo
|
| `` u `` | Check voor updates | |
|
||||||
<kbd>a</kbd>: Alle logs van de branch laten zien
|
| `` <enter> `` | Wissel naar een recente repo | |
|
||||||
</pre>
|
| `` a `` | Alle logs van de branch laten zien | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer commit SHA naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Creëer nieuwe branch van commit
|
| `` o `` | Open commit in browser | |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` n `` | Creëer nieuwe branch van commit | |
|
||||||
<kbd>c</kbd>: Kopieer commit (cherry-pick)
|
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Start met zoeken
|
| `` <enter> `` | Bekijk gecommite bestanden | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Kopieer submodule naam naar klembord
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: Enter submodule
|
| `` <c-o> `` | Kopieer submodule naam naar klembord | |
|
||||||
<kbd>d</kbd>: Remove submodule
|
| `` <enter> `` | Enter | Enter submodule |
|
||||||
<kbd>u</kbd>: Update submodule
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: Voeg nieuwe submodule toe
|
| `` u `` | Update | Update selected submodule. |
|
||||||
<kbd>e</kbd>: Update submodule URL
|
| `` n `` | Voeg nieuwe submodule toe | |
|
||||||
<kbd>i</kbd>: Initialiseer submodule
|
| `` e `` | Update submodule URL | |
|
||||||
<kbd>b</kbd>: Bekijk bulk submodule opties
|
| `` i `` | Initialize | Initialiseer submodule |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | Bekijk bulk submodule opties | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Uitchecken
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Verwijder tag
|
| `` <space> `` | Uitchecken | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: Push tag
|
| `` n `` | Creëer tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Creëer tag
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | Bekijk commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
+326
-290
@@ -1,333 +1,369 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit Keybindings
|
# Lazygit Skróty klawiszowe
|
||||||
|
|
||||||
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
_Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
|
||||||
|
|
||||||
## Globalne
|
## Globalne skróty klawiszowe
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: Switch to a recent repo
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: Scroll up main panel (fn+up/shift+k)
|
| `` <c-r> `` | Przełącz na ostatnie repozytorium | |
|
||||||
<kbd><pgdown></kbd>: Scroll down main panel (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | Przewiń główne okno w górę | |
|
||||||
<kbd>@</kbd>: Open command log menu
|
| `` <pgdown> (fn+down/shift+j) `` | Przewiń główne okno w dół | |
|
||||||
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
|
| `` @ `` | Pokaż opcje dziennika poleceń | Pokaż opcje dla dziennika poleceń, np. pokazywanie/ukrywanie dziennika poleceń i skupienie na dzienniku poleceń. |
|
||||||
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
|
| `` P `` | Wypchnij | Wypchnij bieżącą gałąź do jej gałęzi nadrzędnej. Jeśli nie skonfigurowano gałęzi nadrzędnej, zostaniesz poproszony o skonfigurowanie gałęzi nadrzędnej. |
|
||||||
<kbd>:</kbd>: Wykonaj własną komendę
|
| `` p `` | Pociągnij | Pociągnij zmiany z zdalnego dla bieżącej gałęzi. Jeśli nie skonfigurowano gałęzi nadrzędnej, zostaniesz poproszony o skonfigurowanie gałęzi nadrzędnej. |
|
||||||
<kbd><c-p></kbd>: View custom patch options
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: Widok scalenia/opcje zmiany bazy
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: Odśwież
|
| `` } `` | Zwiększ rozmiar kontekstu w widoku różnic | Zwiększ ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
|
||||||
<kbd>+</kbd>: Next screen mode (normal/half/fullscreen)
|
| `` { `` | Zmniejsz rozmiar kontekstu w widoku różnic | Zmniejsz ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
|
||||||
<kbd>_</kbd>: Prev screen mode
|
| `` : `` | Wykonaj polecenie niestandardowe | Wyświetl monit, w którym możesz wprowadzić polecenie powłoki do wykonania. Nie należy mylić z wcześniej skonfigurowanymi poleceniami niestandardowymi. |
|
||||||
<kbd>?</kbd>: Open menu
|
| `` <c-p> `` | Wyświetl opcje niestandardowej łatki | |
|
||||||
<kbd><c-s></kbd>: View filter-by-path options
|
| `` m `` | Pokaż opcje scalania/rebase | Pokaż opcje do przerwania/kontynuowania/pominięcia bieżącego scalania/rebase. |
|
||||||
<kbd>W</kbd>: Open diff menu
|
| `` R `` | Odśwież | Odśwież stan git (tj. uruchom `git status`, `git branch`, itp. w tle, aby zaktualizować zawartość paneli). To nie uruchamia `git fetch`. |
|
||||||
<kbd><c-e></kbd>: Open diff menu
|
| `` + `` | Następny tryb ekranu (normalny/półpełny/pełnoekranowy) | |
|
||||||
<kbd><c-w></kbd>: Toggle whether or not whitespace changes are shown in the diff view
|
| `` _ `` | Poprzedni tryb ekranu | |
|
||||||
<kbd>z</kbd>: Undo
|
| `` ? `` | Otwórz menu przypisań klawiszy | |
|
||||||
<kbd><c-z></kbd>: Redo
|
| `` <c-s> `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. |
|
||||||
<kbd>P</kbd>: Push
|
| `` W `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. |
|
||||||
<kbd>p</kbd>: Pull
|
| `` <c-e> `` | Pokaż opcje różnicowania | Pokaż opcje dotyczące różnicowania dwóch refów, np. różnicowanie względem wybranego refa, wprowadzanie refa do różnicowania i odwracanie kierunku różnic. |
|
||||||
</pre>
|
| `` q `` | Wyjdź | |
|
||||||
|
| `` <esc> `` | Anuluj | |
|
||||||
|
| `` <c-w> `` | Przełącz białe znaki | Przełącz czy zmiany białych znaków są pokazywane w widoku różnic. |
|
||||||
|
| `` z `` | Cofnij | Dziennik reflog zostanie użyty do określenia, jakie polecenie git należy uruchomić, aby cofnąć ostatnie polecenie git. Nie obejmuje to zmian w drzewie roboczym; brane są pod uwagę tylko commity. |
|
||||||
|
| `` <c-z> `` | Ponów | Dziennik reflog zostanie użyty do określenia, jakie polecenie git należy uruchomić, aby ponowić ostatnie polecenie git. Nie obejmuje to zmian w drzewie roboczym; brane są pod uwagę tylko commity. |
|
||||||
|
|
||||||
## List panel navigation
|
## Nawigacja panelu listy
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: Previous page
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: Next page
|
| `` , `` | Poprzednia strona | |
|
||||||
<kbd><</kbd>: Scroll to top
|
| `` . `` | Następna strona | |
|
||||||
<kbd>></kbd>: Scroll to bottom
|
| `` < `` | Przewiń do góry | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` > `` | Przewiń do dołu | |
|
||||||
<kbd>H</kbd>: Scroll left
|
| `` v `` | Przełącz zaznaczenie zakresu | |
|
||||||
<kbd>L</kbd>: Scroll right
|
| `` <s-down> `` | Zaznacz zakres w dół | |
|
||||||
<kbd>]</kbd>: Next tab
|
| `` <s-up> `` | Zaznacz zakres w górę | |
|
||||||
<kbd>[</kbd>: Previous tab
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
</pre>
|
| `` H `` | Przewiń w lewo | |
|
||||||
|
| `` L `` | Przewiń w prawo | |
|
||||||
## Commit summary
|
| `` ] `` | Następna zakładka | |
|
||||||
|
| `` [ `` | Poprzednia zakładka | |
|
||||||
<pre>
|
|
||||||
<kbd><enter></kbd>: Potwierdź
|
|
||||||
<kbd><esc></kbd>: Zamknij
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Commity
|
## Commity
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
<kbd>b</kbd>: View bisect options
|
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
<kbd>s</kbd>: Ściśnij
|
| `` b `` | Zobacz opcje bisect | |
|
||||||
<kbd>f</kbd>: Napraw commit
|
| `` s `` | Scal | Scal wybrany commit z commitami poniżej. Wiadomość wybranego commita zostanie dołączona do commita poniżej. |
|
||||||
<kbd>r</kbd>: Zmień nazwę commita
|
| `` f `` | Poprawka | Włącz wybrany commit do commita poniżej. Podobnie do fixup, ale wiadomość wybranego commita zostanie odrzucona. |
|
||||||
<kbd>R</kbd>: Zmień nazwę commita w edytorze
|
| `` r `` | Przeformułuj | Przeformułuj wiadomość wybranego commita. |
|
||||||
<kbd>d</kbd>: Usuń commit
|
| `` R `` | Przeformułuj za pomocą edytora | |
|
||||||
<kbd>e</kbd>: Edytuj commit
|
| `` d `` | Usuń | Usuń wybrany commit. To usunie commit z gałęzi za pomocą rebazowania. Jeśli commit wprowadza zmiany, od których zależą późniejsze commity, być może będziesz musiał rozwiązać konflikty scalania. |
|
||||||
<kbd>p</kbd>: Wybierz commit (podczas zmiany bazy)
|
| `` e `` | Edytuj (rozpocznij interaktywne rebazowanie) | Edytuj wybrany commit. Użyj tego, aby rozpocząć interaktywne rebazowanie od wybranego commita. Podczas trwania rebazowania, to oznaczy wybrany commit do edycji, co oznacza, że po kontynuacji rebazowania, rebazowanie zostanie wstrzymane na wybranym commicie, aby umożliwić wprowadzenie zmian. |
|
||||||
<kbd>F</kbd>: Utwórz commit naprawczy dla tego commita
|
| `` i `` | Rozpocznij interaktywny rebase | Rozpocznij interaktywny rebase dla commitów na twoim branchu. To będzie zawierać wszystkie commity od HEAD do pierwszego commita scalenia lub commita głównego brancha.
|
||||||
<kbd>S</kbd>: Spłaszcz wszystkie commity naprawcze powyżej zaznaczonych commitów (autosquash)
|
Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, naciśnij `e`. |
|
||||||
<kbd><c-j></kbd>: Przenieś commit 1 w dół
|
| `` p `` | Wybierz | Oznacz wybrany commit do wybrania (podczas rebazowania). Oznacza to, że commit zostanie zachowany po kontynuacji rebazowania. |
|
||||||
<kbd><c-k></kbd>: Przenieś commit 1 w górę
|
| `` F `` | Utwórz commit fixup | Utwórz commit 'fixup!' dla wybranego commita. Później możesz nacisnąć `S` na tym samym commicie, aby zastosować wszystkie powyższe commity fixup. |
|
||||||
<kbd>v</kbd>: Wklej commity (przebieranie)
|
| `` S `` | Zastosuj commity fixup | Scal wszystkie commity 'fixup!', albo powyżej wybranego commita, albo wszystkie w bieżącej gałęzi (autosquash). |
|
||||||
<kbd>A</kbd>: Popraw commit zmianami z poczekalni
|
| `` <c-j> `` | Przesuń commit w dół | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | Przesuń commit w górę | |
|
||||||
<kbd>t</kbd>: Odwróć commit
|
| `` V `` | Wklej (cherry-pick) | |
|
||||||
<kbd>T</kbd>: Tag commit
|
| `` B `` | Oznacz jako bazowy commit dla rebase | Wybierz bazowy commit dla następnego rebase. Kiedy robisz rebase na branch, tylko commity powyżej bazowego commita zostaną przeniesione. Używa to polecenia `git rebase --onto`. |
|
||||||
<kbd><c-l></kbd>: Open log menu
|
| `` A `` | Popraw | Popraw commit ze zmianami zatwierdzonymi. Jeśli wybrany commit jest commit HEAD, to wykona `git commit --amend`. W przeciwnym razie commit zostanie poprawiony za pomocą rebazowania. |
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` a `` | Popraw atrybut commita | Ustaw/Resetuj autora commita lub ustaw współautora. |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` t `` | Cofnij | Utwórz commit cofający dla wybranego commita, który stosuje zmiany wybranego commita w odwrotnej kolejności. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` T `` | Otaguj commit | Utwórz nowy tag wskazujący na wybrany commit. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` <c-l> `` | Zobacz opcje logów | Zobacz opcje dla logów commitów, np. zmiana kolejności sortowania, ukrywanie grafu gita, pokazywanie całego grafu gita. |
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
<kbd>c</kbd>: Kopiuj commit (przebieranie)
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
</pre>
|
| `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć `<esc>`, aby anulować zaznaczenie. |
|
||||||
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
|
| `` <enter> `` | Wyświetl pliki | |
|
||||||
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Confirmation panel
|
## Drzewa pracy
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Potwierdź
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Zamknij
|
| `` n `` | Nowe drzewo pracy | |
|
||||||
</pre>
|
| `` <space> `` | Przełącz | Przełącz do wybranego drzewa pracy. |
|
||||||
|
| `` o `` | Otwórz w edytorze | |
|
||||||
|
| `` d `` | Usuń | Usuń wybrane drzewo pracy. To usunie zarówno katalog drzewa pracy, jak i metadane o drzewie pracy w katalogu .git. |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Local branches
|
## Główny panel (budowanie łatki)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy branch name to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Show git-flow options
|
| `` <left> `` | Idź do poprzedniego fragmentu | |
|
||||||
<kbd><space></kbd>: Przełącz
|
| `` <right> `` | Idź do następnego fragmentu | |
|
||||||
<kbd>n</kbd>: Nowa gałąź
|
| `` v `` | Przełącz zaznaczenie zakresu | |
|
||||||
<kbd>o</kbd>: Utwórz żądanie pobrania
|
| `` a `` | Zaznacz fragment | Przełącz tryb zaznaczania fragmentu. |
|
||||||
<kbd>O</kbd>: Utwórz opcje żądania ściągnięcia
|
| `` <c-o> `` | Kopiuj zaznaczony tekst do schowka | |
|
||||||
<kbd><c-y></kbd>: Skopiuj adres URL żądania pobrania do schowka
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
<kbd>c</kbd>: Przełącz używając nazwy
|
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
||||||
<kbd>F</kbd>: Wymuś przełączenie
|
| `` <space> `` | Przełącz linie w łatce | |
|
||||||
<kbd>d</kbd>: Usuń gałąź
|
| `` <esc> `` | Wyjdź z budowniczego niestandardowej łatki | |
|
||||||
<kbd>r</kbd>: Zmiana bazy gałęzi
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
<kbd>M</kbd>: Scal do obecnej gałęzi
|
|
||||||
<kbd>f</kbd>: Fast-forward this branch from its upstream
|
|
||||||
<kbd>T</kbd>: Create tag
|
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
|
||||||
<kbd>R</kbd>: Rename branch
|
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
|
||||||
<kbd><enter></kbd>: View commits
|
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Main panel (patch building)
|
## Lokalne gałęzie
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Poprzedni kawałek
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Następny kawałek
|
| `` <c-o> `` | Kopiuj nazwę gałęzi do schowka | |
|
||||||
<kbd>v</kbd>: Toggle drag select
|
| `` i `` | Pokaż opcje git-flow | |
|
||||||
<kbd>V</kbd>: Toggle drag select
|
| `` <space> `` | Przełącz | Przełącz wybrany element. |
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
| `` n `` | Nowa gałąź | |
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
| `` o `` | Utwórz żądanie ściągnięcia | |
|
||||||
<kbd>o</kbd>: Otwórz plik
|
| `` O `` | Zobacz opcje tworzenia pull requesta | |
|
||||||
<kbd>e</kbd>: Edytuj plik
|
| `` <c-y> `` | Kopiuj adres URL żądania ściągnięcia do schowka | |
|
||||||
<kbd><space></kbd>: Add/Remove line(s) to patch
|
| `` c `` | Przełącz według nazwy | Przełącz według nazwy. W polu wprowadzania możesz wpisać '-' aby przełączyć się na ostatnią gałąź. |
|
||||||
<kbd><esc></kbd>: Wyście z trybu "linia po linii"
|
| `` F `` | Wymuś przełączenie | Wymuś przełączenie wybranej gałęzi. To spowoduje odrzucenie wszystkich lokalnych zmian w drzewie roboczym przed przełączeniem na wybraną gałąź. |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnej/odległej gałęzi. |
|
||||||
</pre>
|
| `` r `` | Przebazuj | Przebazuj przełączoną gałąź na wybraną gałąź. |
|
||||||
|
| `` M `` | Scal | Scal wybraną gałąź z aktualnie sprawdzoną gałęzią. |
|
||||||
|
| `` f `` | Szybkie przewijanie | Szybkie przewijanie wybranej gałęzi z jej źródła. |
|
||||||
|
| `` T `` | Nowy tag | |
|
||||||
|
| `` s `` | Kolejność sortowania | |
|
||||||
|
| `` g `` | Reset | |
|
||||||
|
| `` R `` | Zmień nazwę gałęzi | |
|
||||||
|
| `` u `` | Pokaż opcje upstream | Pokaż opcje dotyczące upstream gałęzi, np. ustawianie/usuwanie upstream i resetowanie do upstream. |
|
||||||
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
|
| `` <enter> `` | Pokaż commity | |
|
||||||
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Wykonaj
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Zamknij
|
| `` <enter> `` | Wykonaj | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | Zamknij | |
|
||||||
</pre>
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
|
## Panel główny (normalny)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` mouse wheel down (fn+up) `` | Przewiń w dół | |
|
||||||
|
| `` mouse wheel up (fn+down) `` | Przewiń w górę | |
|
||||||
|
|
||||||
|
## Panel główny (scalanie)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <space> `` | Wybierz fragment | |
|
||||||
|
| `` b `` | Wybierz wszystkie fragmenty | |
|
||||||
|
| `` <up> `` | Poprzedni fragment | |
|
||||||
|
| `` <down> `` | Następny fragment | |
|
||||||
|
| `` <left> `` | Poprzedni konflikt | |
|
||||||
|
| `` <right> `` | Następny konflikt | |
|
||||||
|
| `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. |
|
||||||
|
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
|
||||||
|
| `` <esc> `` | Wróć do panelu plików | |
|
||||||
|
|
||||||
|
## Panel główny (zatwierdzanie)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <left> `` | Idź do poprzedniego fragmentu | |
|
||||||
|
| `` <right> `` | Idź do następnego fragmentu | |
|
||||||
|
| `` v `` | Przełącz zaznaczenie zakresu | |
|
||||||
|
| `` a `` | Zaznacz fragment | Przełącz tryb zaznaczania fragmentu. |
|
||||||
|
| `` <c-o> `` | Kopiuj zaznaczony tekst do schowka | |
|
||||||
|
| `` <space> `` | Zatwierdź | Przełącz zaznaczenie zatwierdzone/niezatwierdzone. |
|
||||||
|
| `` d `` | Odrzuć | Gdy zaznaczona jest niezatwierdzona zmiana, odrzuć ją używając `git reset`. Gdy zaznaczona jest zatwierdzona zmiana, cofnij zatwierdzenie. |
|
||||||
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` <esc> `` | Wróć do panelu plików | |
|
||||||
|
| `` <tab> `` | Przełącz widok | Przełącz na inny widok (zatwierdzone/niezatwierdzone zmiany). |
|
||||||
|
| `` E `` | Edytuj fragment | Edytuj wybrany fragment w zewnętrznym edytorze. |
|
||||||
|
| `` c `` | Commit | Zatwierdź zmiany zatwierdzone. |
|
||||||
|
| `` w `` | Zatwierdź zmiany bez hooka pre-commit | |
|
||||||
|
| `` C `` | Zatwierdź zmiany używając edytora git | |
|
||||||
|
| `` <c-f> `` | Znajdź bazowy commit do poprawki | Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
|
## Panel potwierdzenia
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Potwierdź | |
|
||||||
|
| `` <esc> `` | Zamknij/Anuluj | |
|
||||||
|
|
||||||
## Pliki
|
## Pliki
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Pokaż opcje porzucania zmian
|
| `` <c-o> `` | Kopiuj ścieżkę do schowka | |
|
||||||
<kbd><space></kbd>: Przełącz stan poczekalni
|
| `` <space> `` | Zatwierdź | Przełącz zatwierdzenie dla wybranego pliku. |
|
||||||
<kbd><c-b></kbd>: Filter files by status
|
| `` <c-b> `` | Filtruj pliki według statusu | |
|
||||||
<kbd>c</kbd>: Zatwierdź zmiany
|
| `` y `` | Kopiuj do schowka | |
|
||||||
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
| `` c `` | Commit | Zatwierdź zmiany zatwierdzone. |
|
||||||
<kbd>A</kbd>: Zmień ostatni commit
|
| `` w `` | Zatwierdź zmiany bez hooka pre-commit | |
|
||||||
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
|
| `` A `` | Popraw ostatni commit | |
|
||||||
<kbd>e</kbd>: Edytuj plik
|
| `` C `` | Zatwierdź zmiany używając edytora git | |
|
||||||
<kbd>o</kbd>: Otwórz plik
|
| `` <c-f> `` | Znajdź bazowy commit do poprawki | Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: Ignore or exclude file
|
| `` e `` | Edytuj | Otwórz plik w zewnętrznym edytorze. |
|
||||||
<kbd>r</kbd>: Odśwież pliki
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
<kbd>s</kbd>: Przechowaj zmiany
|
| `` i `` | Ignoruj lub wyklucz plik | |
|
||||||
<kbd>S</kbd>: Wyświetl opcje schowka
|
| `` r `` | Odśwież pliki | |
|
||||||
<kbd>a</kbd>: Przełącz stan poczekalni wszystkich
|
| `` s `` | Schowaj | Schowaj wszystkie zmiany. Dla innych wariantów schowania, użyj klawisza wyświetlania opcji schowka. |
|
||||||
<kbd><enter></kbd>: Zatwierdź pojedyncze linie
|
| `` S `` | Wyświetl opcje schowka | Wyświetl opcje schowka (np. schowaj wszystko, schowaj zatwierdzone, schowaj niezatwierdzone). |
|
||||||
<kbd>g</kbd>: View upstream reset options
|
| `` a `` | Zatwierdź wszystko | Przełącz zatwierdzenie/odznaczenie dla wszystkich plików w drzewie roboczym. |
|
||||||
<kbd>D</kbd>: Wyświetl opcje resetu
|
| `` <enter> `` | Zatwierdź linie / Zwiń katalog | Jeśli wybrany element jest plikiem, skup się na widoku zatwierdzania, aby móc zatwierdzać poszczególne fragmenty/linie. Jeśli wybrany element jest katalogiem, zwiń/rozwiń go. |
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
| `` d `` | Odrzuć | Wyświetl opcje odrzucania zmian w wybranym pliku. |
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
| `` g `` | Pokaż opcje resetowania do upstream | |
|
||||||
<kbd>f</kbd>: Pobierz
|
| `` D `` | Reset | Wyświetl opcje resetu dla drzewa roboczego (np. zniszczenie drzewa roboczego). |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` ` `` | Przełącz widok drzewa plików | Przełącz widok plików między płaskim a drzewem. Płaski układ pokazuje wszystkie ścieżki plików na jednej liście, układ drzewa grupuje pliki według katalogów. |
|
||||||
</pre>
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
|
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
|
||||||
|
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Pliki commita
|
## Pliki commita
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy the committed file name to the clipboard
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Plik wybierania
|
| `` <c-o> `` | Kopiuj ścieżkę do schowka | |
|
||||||
<kbd>d</kbd>: Porzuć zmiany commita dla tego pliku
|
| `` c `` | Przełącz | Przełącz plik. Zastępuje plik w twoim drzewie roboczym wersją z wybranego commita. |
|
||||||
<kbd>o</kbd>: Otwórz plik
|
| `` d `` | Usuń | Odrzuć zmiany w tym pliku z tego commita. Uruchamia interaktywny rebase w tle, więc możesz otrzymać konflikt scalania, jeśli późniejszy commit również zmienia ten plik. |
|
||||||
<kbd>e</kbd>: Edytuj plik
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
<kbd><space></kbd>: Toggle file included in patch
|
| `` e `` | Edytuj | Otwórz plik w zewnętrznym edytorze. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
| `` <space> `` | Przełącz plik włączony w łatkę | Przełącz, czy plik jest włączony w niestandardową łatkę. Zobacz https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
| `` a `` | Przełącz wszystkie pliki | Dodaj/usuń wszystkie pliki commita do niestandardowej łatki. Zobacz https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` <enter> `` | Wejdź do pliku / Przełącz zwiń katalog | Jeśli plik jest wybrany, wejdź do pliku, aby móc dodawać/usuwać poszczególne linie do niestandardowej łatki. Jeśli wybrany jest katalog, przełącz katalog. |
|
||||||
</pre>
|
| `` ` `` | Przełącz widok drzewa plików | Przełącz widok plików między płaskim a drzewem. Płaski układ pokazuje wszystkie ścieżki plików na jednej liście, układ drzewa grupuje pliki według katalogów. |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Poczekalnia
|
## Podsumowanie commita
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Poprzedni kawałek
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Następny kawałek
|
| `` <enter> `` | Potwierdź | |
|
||||||
<kbd>v</kbd>: Toggle drag select
|
| `` <esc> `` | Zamknij | |
|
||||||
<kbd>V</kbd>: Toggle drag select
|
|
||||||
<kbd>a</kbd>: Toggle select hunk
|
|
||||||
<kbd><c-o></kbd>: Copy the selected text to the clipboard
|
|
||||||
<kbd>o</kbd>: Otwórz plik
|
|
||||||
<kbd>e</kbd>: Edytuj plik
|
|
||||||
<kbd><esc></kbd>: Wróć do panelu plików
|
|
||||||
<kbd><tab></kbd>: Switch to other panel (staged/unstaged changes)
|
|
||||||
<kbd><space></kbd>: Toggle line staged / unstaged
|
|
||||||
<kbd>d</kbd>: Discard change (git reset)
|
|
||||||
<kbd>E</kbd>: Edit hunk
|
|
||||||
<kbd>c</kbd>: Zatwierdź zmiany
|
|
||||||
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
|
||||||
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
|
|
||||||
<kbd>/</kbd>: Search the current view by text
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
<kbd>c</kbd>: Kopiuj commit (przebieranie)
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
| `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć `<esc>`, aby anulować zaznaczenie. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Pokaż commity | |
|
||||||
</pre>
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
## Remote branches
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd><c-o></kbd>: Copy branch name to clipboard
|
|
||||||
<kbd><space></kbd>: Przełącz
|
|
||||||
<kbd>n</kbd>: Nowa gałąź
|
|
||||||
<kbd>M</kbd>: Scal do obecnej gałęzi
|
|
||||||
<kbd>r</kbd>: Zmiana bazy gałęzi
|
|
||||||
<kbd>d</kbd>: Usuń gałąź
|
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
|
||||||
<kbd><enter></kbd>: View commits
|
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Remotes
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd>f</kbd>: Fetch remote
|
|
||||||
<kbd>n</kbd>: Add new remote
|
|
||||||
<kbd>d</kbd>: Remove remote
|
|
||||||
<kbd>e</kbd>: Edit remote
|
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Scalanie
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd>e</kbd>: Edytuj plik
|
|
||||||
<kbd>o</kbd>: Otwórz plik
|
|
||||||
<kbd><left></kbd>: Poprzedni konflikt
|
|
||||||
<kbd><right></kbd>: Następny konflikt
|
|
||||||
<kbd><up></kbd>: Wybierz poprzedni kawałek
|
|
||||||
<kbd><down></kbd>: Wybierz następny kawałek
|
|
||||||
<kbd>z</kbd>: Cofnij
|
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
|
||||||
<kbd><space></kbd>: Wybierz kawałek
|
|
||||||
<kbd>b</kbd>: Wybierz oba kawałki
|
|
||||||
<kbd><esc></kbd>: Wróć do panelu plików
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Schowek
|
## Schowek
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Zastosuj
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Wyciągnij
|
| `` <space> `` | Zastosuj | Zastosuj wpis schowka do katalogu roboczego. |
|
||||||
<kbd>d</kbd>: Porzuć
|
| `` g `` | Wyciągnij | Zastosuj wpis schowka do katalogu roboczego i usuń wpis schowka. |
|
||||||
<kbd>n</kbd>: Nowa gałąź
|
| `` d `` | Usuń | Usuń wpis schowka z listy schowka. |
|
||||||
<kbd>r</kbd>: Rename stash
|
| `` n `` | Nowa gałąź | Utwórz nową gałąź z wybranego wpisu schowka. Działa poprzez przełączenie git na commit, na którym wpis schowka został utworzony, tworzenie nowej gałęzi z tego commita, a następnie zastosowanie wpisu schowka do nowej gałęzi jako dodatkowego commita. |
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
| `` r `` | Zmień nazwę schowka | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Wyświetl pliki | |
|
||||||
</pre>
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: Otwórz konfigurację
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: Edytuj konfigurację
|
| `` o `` | Otwórz plik konfiguracyjny | Otwórz plik w domyślnej aplikacji. |
|
||||||
<kbd>u</kbd>: Sprawdź aktualizacje
|
| `` e `` | Edytuj plik konfiguracyjny | Otwórz plik w zewnętrznym edytorze. |
|
||||||
<kbd><enter></kbd>: Switch to a recent repo
|
| `` u `` | Sprawdź aktualizacje | |
|
||||||
<kbd>a</kbd>: Pokaż wszystkie logi gałęzi
|
| `` <enter> `` | Przełącz na ostatnie repozytorium | |
|
||||||
</pre>
|
| `` a `` | Pokaż wszystkie gałęzie w logach | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commity
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy commit SHA to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Checkout commit
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
<kbd>o</kbd>: Open commit in browser
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
<kbd>n</kbd>: Create new branch off of commit
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
<kbd>c</kbd>: Kopiuj commit (przebieranie)
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
| `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć `<esc>`, aby anulować zaznaczenie. |
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
<kbd>/</kbd>: Search the current view by text
|
| `` <enter> `` | Wyświetl pliki | |
|
||||||
</pre>
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Submodules
|
## Submoduły
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Copy submodule name to clipboard
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: Enter submodule
|
| `` <c-o> `` | Kopiuj nazwę submodułu do schowka | |
|
||||||
<kbd>d</kbd>: Remove submodule
|
| `` <enter> `` | Wejdź | Wejdź do submodułu. Po wejściu do submodułu możesz nacisnąć `<esc>`, aby wrócić do repozytorium nadrzędnego. |
|
||||||
<kbd>u</kbd>: Update submodule
|
| `` d `` | Usuń | Usuń wybrany submoduł i odpowiadający mu katalog. |
|
||||||
<kbd>n</kbd>: Add new submodule
|
| `` u `` | Aktualizuj | Aktualizuj wybrany submoduł. |
|
||||||
<kbd>e</kbd>: Update submodule URL
|
| `` n `` | Nowy submoduł | |
|
||||||
<kbd>i</kbd>: Initialize submodule
|
| `` e `` | Zaktualizuj URL submodułu | |
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
| `` i `` | Zainicjuj | Zainicjuj wybrany submoduł, aby przygotować do pobrania. Prawdopodobnie chcesz to kontynuować, wywołując akcję 'update', aby pobrać submoduł. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | Pokaż opcje masowych operacji na submodułach | |
|
||||||
</pre>
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Tags
|
## Tagi
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Przełącz
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Delete tag
|
| `` <space> `` | Przełącz | Przełącz wybrany tag jako odłączoną głowę (detached HEAD). |
|
||||||
<kbd>P</kbd>: Push tag
|
| `` n `` | Nowy tag | Utwórz nowy tag z bieżącego commita. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
|
||||||
<kbd>n</kbd>: Create tag
|
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnego/odległego tagu. |
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
| `` P `` | Wyślij tag | Wyślij wybrany tag do zdalnego. Zostaniesz poproszony o wybranie zdalnego. |
|
||||||
<kbd><enter></kbd>: View commits
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | Pokaż commity | |
|
||||||
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Zwykłe
|
## Zdalne
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: Przewiń w dół (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: Przewiń w górę (fn+down)
|
| `` <enter> `` | Wyświetl gałęzie | |
|
||||||
</pre>
|
| `` n `` | Nowy zdalny | |
|
||||||
|
| `` d `` | Usuń | Usuń wybrany zdalny. Wszelkie lokalne gałęzie śledzące gałąź zdalną z tego zdalnego nie zostaną dotknięte. |
|
||||||
|
| `` e `` | Edytuj | Edytuj nazwę lub URL wybranego zdalnego. |
|
||||||
|
| `` f `` | Pobierz | Pobierz aktualizacje z zdalnego repozytorium. Pobiera nowe commity i gałęzie bez scalania ich z lokalnymi gałęziami. |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
|
## Zdalne gałęzie
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj nazwę gałęzi do schowka | |
|
||||||
|
| `` <space> `` | Przełącz | Przełącz na nową lokalną gałąź na podstawie wybranej gałęzi zdalnej. Nowa gałąź będzie śledzić gałąź zdalną. |
|
||||||
|
| `` n `` | Nowa gałąź | |
|
||||||
|
| `` M `` | Scal | Scal wybraną gałąź z aktualnie sprawdzoną gałęzią. |
|
||||||
|
| `` r `` | Przebazuj | Przebazuj przełączoną gałąź na wybraną gałąź. |
|
||||||
|
| `` d `` | Usuń | Usuń gałąź zdalną ze zdalnego. |
|
||||||
|
| `` u `` | Ustaw jako upstream | Ustaw wybraną gałąź zdalną jako upstream sprawdzonej gałęzi. |
|
||||||
|
| `` s `` | Kolejność sortowania | |
|
||||||
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
|
| `` <enter> `` | Pokaż commity | |
|
||||||
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|||||||
+302
-266
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit Связки клавиш
|
# Lazygit Связки клавиш
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Связки клавиш_
|
|||||||
|
|
||||||
## Глобальные сочетания клавиш
|
## Глобальные сочетания клавиш
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: Переключиться на последний репозиторий
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: Прокрутить вверх главную панель (fn+up/shift+k)
|
| `` <c-r> `` | Переключиться на последний репозиторий | |
|
||||||
<kbd><pgdown></kbd>: Прокрутить вниз главную панель (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | Прокрутить вверх главную панель | |
|
||||||
<kbd>@</kbd>: Открыть меню журнала команд
|
| `` <pgdown> (fn+down/shift+j) `` | Прокрутить вниз главную панель | |
|
||||||
<kbd>}</kbd>: Увеличить размер контекста, отображаемого вокруг изменений в просмотрщике сравнении
|
| `` @ `` | Открыть меню журнала команд | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении
|
| `` P `` | Отправить изменения | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: Выполнить пользовательскую команду
|
| `` p `` | Получить и слить изменения | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: Просмотреть пользовательские параметры патча
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: Просмотреть параметры слияния/перебазирования
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: Обновить
|
| `` } `` | Увеличить размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: Следующий режим экрана (нормальный/полуэкранный/полноэкранный)
|
| `` { `` | Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: Предыдущий режим экрана
|
| `` : `` | Выполнить пользовательскую команду | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: Открыть меню
|
| `` <c-p> `` | Просмотреть пользовательские параметры патча | |
|
||||||
<kbd><c-s></kbd>: Просмотреть параметры фильтрации по пути
|
| `` m `` | Просмотреть параметры слияния/перебазирования | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: Открыть меню сравнении
|
| `` R `` | Обновить | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: Открыть меню сравнении
|
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
|
||||||
<kbd><c-w></kbd>: Переключить отображение изменении пробелов в просмотрщике сравнении
|
| `` _ `` | Предыдущий режим экрана | |
|
||||||
<kbd>z</kbd>: Отменить (через reflog) (экспериментальный)
|
| `` ? `` | Открыть меню | |
|
||||||
<kbd><c-z></kbd>: Повторить (через reflog) (экспериментальный)
|
| `` <c-s> `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: Отправить изменения
|
| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: Получить и слить изменения
|
| `` <c-e> `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | Выйти | |
|
||||||
|
| `` <esc> `` | Отменить | |
|
||||||
|
| `` <c-w> `` | Переключить отображение изменении пробелов в просмотрщике сравнении | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | Отменить (через reflog) (экспериментальный) | Журнал ссылок (reflog) будет использоваться для определения того, какую команду git запустить, чтобы отменить последнюю команду git. Сюда не входят изменения в рабочем дереве; учитываются только коммиты. |
|
||||||
|
| `` <c-z> `` | Повторить (через reflog) (экспериментальный) | Журнал ссылок (reflog) будет использоваться для определения того, какую команду git нужно запустить, чтобы повторить последнюю команду git. Сюда не входят изменения в рабочем дереве; учитываются только коммиты. |
|
||||||
|
|
||||||
## Навигация по панели списка
|
## Навигация по панели списка
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: Предыдущая страница
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: Следующая страница
|
| `` , `` | Предыдущая страница | |
|
||||||
<kbd><</kbd>: Пролистать наверх
|
| `` . `` | Следующая страница | |
|
||||||
<kbd>></kbd>: Прокрутить вниз
|
| `` < `` | Пролистать наверх | |
|
||||||
<kbd>/</kbd>: Найти
|
| `` > `` | Прокрутить вниз | |
|
||||||
<kbd>H</kbd>: Прокрутить влево
|
| `` v `` | Переключить выборку перетаскивания | |
|
||||||
<kbd>L</kbd>: Прокрутить вправо
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: Следующая вкладка
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: Предыдущая вкладка
|
| `` / `` | Найти | |
|
||||||
</pre>
|
| `` H `` | Прокрутить влево | |
|
||||||
|
| `` L `` | Прокрутить вправо | |
|
||||||
|
| `` ] `` | Следующая вкладка | |
|
||||||
|
| `` [ `` | Предыдущая вкладка | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Главная панель (Индексирование)
|
## Главная панель (Индексирование)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Выбрать предыдущую часть
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Выбрать следующую часть
|
| `` <left> `` | Выбрать предыдущую часть | |
|
||||||
<kbd>v</kbd>: Переключить выборку перетаскивания
|
| `` <right> `` | Выбрать следующую часть | |
|
||||||
<kbd>V</kbd>: Переключить выборку перетаскивания
|
| `` v `` | Переключить выборку перетаскивания | |
|
||||||
<kbd>a</kbd>: Переключить выборку частей
|
| `` a `` | Переключить выборку частей | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Скопировать выделенный текст в буфер обмена
|
| `` <c-o> `` | Скопировать выделенный текст в буфер обмена | |
|
||||||
<kbd>o</kbd>: Открыть файл
|
| `` <space> `` | Переключить индекс | Переключить строку в проиндексированные / непроиндексированные |
|
||||||
<kbd>e</kbd>: Редактировать файл
|
| `` d `` | Отменить изменение (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: Вернуться к панели файлов
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
<kbd><tab></kbd>: Переключиться на другую панель (проиндексированные/непроиндексированные изменения)
|
| `` e `` | Редактировать файл | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Переключить строку в проиндексированные / непроиндексированные
|
| `` <esc> `` | Вернуться к панели файлов | |
|
||||||
<kbd>d</kbd>: Отменить изменение (git reset)
|
| `` <tab> `` | Переключиться на другую панель (проиндексированные/непроиндексированные изменения) | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Изменить эту часть
|
| `` E `` | Изменить эту часть | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: Сохранить изменения
|
| `` c `` | Сохранить изменения | Commit staged changes. |
|
||||||
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
|
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
|
||||||
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
|
| `` C `` | Сохранить изменения с помощью редактора git | |
|
||||||
<kbd>/</kbd>: Найти
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Главная панель (Обычный)
|
## Главная панель (Обычный)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: Прокрутить вниз (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: Прокрутить вверх (fn+down)
|
| `` mouse wheel down (fn+up) `` | Прокрутить вниз | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | Прокрутить вверх | |
|
||||||
|
|
||||||
## Главная панель (Слияние)
|
## Главная панель (Слияние)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: Редактировать файл
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: Открыть файл
|
| `` <space> `` | Выбрать эту часть | |
|
||||||
<kbd><left></kbd>: Выбрать предыдущий конфликт
|
| `` b `` | Выбрать все части | |
|
||||||
<kbd><right></kbd>: Выбрать следующий конфликт
|
| `` <up> `` | Выбрать предыдущую часть | |
|
||||||
<kbd><up></kbd>: Выбрать предыдущую часть
|
| `` <down> `` | Выбрать следующую часть | |
|
||||||
<kbd><down></kbd>: Выбрать следующую часть
|
| `` <left> `` | Выбрать предыдущий конфликт | |
|
||||||
<kbd>z</kbd>: Отменить
|
| `` <right> `` | Выбрать следующий конфликт | |
|
||||||
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
|
| `` z `` | Отменить | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: Выбрать эту часть
|
| `` e `` | Редактировать файл | Open file in external editor. |
|
||||||
<kbd>b</kbd>: Выбрать все части
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
<kbd><esc></kbd>: Вернуться к панели файлов
|
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | Вернуться к панели файлов | |
|
||||||
|
|
||||||
## Главная панель (сборка патчей)
|
## Главная панель (сборка патчей)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: Выбрать предыдущую часть
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: Выбрать следующую часть
|
| `` <left> `` | Выбрать предыдущую часть | |
|
||||||
<kbd>v</kbd>: Переключить выборку перетаскивания
|
| `` <right> `` | Выбрать следующую часть | |
|
||||||
<kbd>V</kbd>: Переключить выборку перетаскивания
|
| `` v `` | Переключить выборку перетаскивания | |
|
||||||
<kbd>a</kbd>: Переключить выборку частей
|
| `` a `` | Переключить выборку частей | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: Скопировать выделенный текст в буфер обмена
|
| `` <c-o> `` | Скопировать выделенный текст в буфер обмена | |
|
||||||
<kbd>o</kbd>: Открыть файл
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
<kbd>e</kbd>: Редактировать файл
|
| `` e `` | Редактировать файл | Open file in external editor. |
|
||||||
<kbd><space></kbd>: Добавить/удалить строку(и) для патча
|
| `` <space> `` | Добавить/удалить строку(и) для патча | |
|
||||||
<kbd><esc></kbd>: Выйти из сборщика пользовательских патчей
|
| `` <esc> `` | Выйти из сборщика пользовательских патчей | |
|
||||||
<kbd>/</kbd>: Найти
|
| `` / `` | Найти | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## Журнал ссылок (Reflog)
|
## Журнал ссылок (Reflog)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать SHA коммита в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Переключить коммит
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
<kbd>y</kbd>: Скопировать атрибут коммита
|
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Открыть коммит в браузере
|
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Создать новую ветку с этого коммита
|
| `` o `` | Открыть коммит в браузере | |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` n `` | Создать новую ветку с этого коммита | |
|
||||||
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
|
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
| `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Коммиты
|
## Коммиты
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать SHA коммита в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
<kbd>b</kbd>: Просмотреть параметры бинарного поиска
|
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
|
||||||
<kbd>s</kbd>: Объединить несколько коммитов в один нижний
|
| `` b `` | Просмотреть параметры бинарного поиска | |
|
||||||
<kbd>f</kbd>: Объединить несколько коммитов в один отбросив сообщение коммита
|
| `` s `` | Объединить коммиты (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: Перефразировать коммит
|
| `` f `` | Объединить несколько коммитов в один отбросив сообщение коммита (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: Переписать коммит с помощью редактора
|
| `` r `` | Перефразировать коммит | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: Удалить коммит
|
| `` R `` | Переписать коммит с помощью редактора | |
|
||||||
<kbd>e</kbd>: Изменить коммит
|
| `` d `` | Удалить коммит | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: Выбрать коммит (в середине перебазирования)
|
| `` e `` | Edit (start interactive rebase) | Изменить коммит |
|
||||||
<kbd>F</kbd>: Создать fixup коммит для этого коммита
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: Переместить коммит вниз на один
|
| `` p `` | Pick | Выбрать коммит (в середине перебазирования) |
|
||||||
<kbd><c-k></kbd>: Переместить коммит вверх на один
|
| `` F `` | Создать fixup коммит | Создать fixup коммит для этого коммита |
|
||||||
<kbd>v</kbd>: Вставить отобранные коммиты (cherry-pick)
|
| `` S `` | Apply fixup commits | Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение) |
|
||||||
<kbd>A</kbd>: Править последний коммит с проиндексированными изменениями
|
| `` <c-j> `` | Переместить коммит вниз на один | |
|
||||||
<kbd>a</kbd>: Установить/убрать автора коммита
|
| `` <c-k> `` | Переместить коммит вверх на один | |
|
||||||
<kbd>t</kbd>: Отменить коммит
|
| `` V `` | Вставить отобранные коммиты (cherry-pick) | |
|
||||||
<kbd>T</kbd>: Пометить коммит тегом
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: Открыть меню журнала
|
| `` A `` | Amend | Править последний коммит с проиндексированными изменениями |
|
||||||
<kbd><space></kbd>: Переключить коммит
|
| `` a `` | Установить/убрать автора коммита | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: Скопировать атрибут коммита
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: Открыть коммит в браузере
|
| `` T `` | Пометить коммит тегом | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Создать новую ветку с этого коммита
|
| `` <c-l> `` | Открыть меню журнала | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
|
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
| `` o `` | Открыть коммит в браузере | |
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
| `` n `` | Создать новую ветку с этого коммита | |
|
||||||
<kbd>/</kbd>: Найти
|
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Локальные Ветки
|
## Локальные Ветки
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать название ветки в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: Показать параметры git-flow
|
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
|
||||||
<kbd><space></kbd>: Переключить
|
| `` i `` | Показать параметры git-flow | |
|
||||||
<kbd>n</kbd>: Новая ветка
|
| `` <space> `` | Переключить | Checkout selected item. |
|
||||||
<kbd>o</kbd>: Создать запрос на принятие изменений
|
| `` n `` | Новая ветка | |
|
||||||
<kbd>O</kbd>: Создать параметры запроса принятие изменений
|
| `` o `` | Создать запрос на принятие изменений | |
|
||||||
<kbd><c-y></kbd>: Скопировать URL запроса на принятие изменений в буфер обмена
|
| `` O `` | Создать параметры запроса принятие изменений | |
|
||||||
<kbd>c</kbd>: Переключить по названию
|
| `` <c-y> `` | Скопировать URL запроса на принятие изменений в буфер обмена | |
|
||||||
<kbd>F</kbd>: Принудительное переключение
|
| `` c `` | Переключить по названию | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: Удалить ветку
|
| `` F `` | Принудительное переключение | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: Слияние с текущей переключённой веткой
|
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: Перемотать эту ветку вперёд из её upstream-ветки
|
| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: Создать тег
|
| `` f `` | Перемотать эту ветку вперёд из её upstream-ветки | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` T `` | Создать тег | |
|
||||||
<kbd>R</kbd>: Переименовать ветку
|
| `` s `` | Порядок сортировки | |
|
||||||
<kbd>u</kbd>: Установить/убрать upstream-ветку
|
| `` g `` | Просмотреть параметры сброса | |
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
| `` R `` | Переименовать ветку | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Меню
|
## Меню
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Выполнить
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Закрыть
|
| `` <enter> `` | Выполнить | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | Закрыть | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Панель Подтверждения
|
## Панель Подтверждения
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Подтвердить
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Закрыть/отменить
|
| `` <enter> `` | Подтвердить | |
|
||||||
</pre>
|
| `` <esc> `` | Закрыть/отменить | |
|
||||||
|
|
||||||
## Подкоммиты
|
## Подкоммиты
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать SHA коммита в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Переключить коммит
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
<kbd>y</kbd>: Скопировать атрибут коммита
|
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: Открыть коммит в браузере
|
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: Создать новую ветку с этого коммита
|
| `` o `` | Открыть коммит в браузере | |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` n `` | Создать новую ветку с этого коммита | |
|
||||||
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
|
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
| `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Найти
|
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Подмодули
|
## Подмодули
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать название подмодуля в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: Ввести подмодуль
|
| `` <c-o> `` | Скопировать название подмодуля в буфер обмена | |
|
||||||
<kbd>d</kbd>: Удалить подмодуль
|
| `` <enter> `` | Enter | Ввести подмодуль |
|
||||||
<kbd>u</kbd>: Обновить подмодуль
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: Добавить новый подмодуль
|
| `` u `` | Update | Обновить подмодуль |
|
||||||
<kbd>e</kbd>: Обновить URL подмодуля
|
| `` n `` | Добавить новый подмодуль | |
|
||||||
<kbd>i</kbd>: Инициализировать подмодуль
|
| `` e `` | Обновить URL подмодуля | |
|
||||||
<kbd>b</kbd>: Просмотреть параметры массового подмодуля
|
| `` i `` | Initialize | Инициализировать подмодуль |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | Просмотреть параметры массового подмодуля | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Сводка коммита
|
## Сводка коммита
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: Подтвердить
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: Закрыть
|
| `` <enter> `` | Подтвердить | |
|
||||||
</pre>
|
| `` <esc> `` | Закрыть | |
|
||||||
|
|
||||||
## Сохранить Изменения Файлов
|
## Сохранить Изменения Файлов
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать закомиченное имя файла в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: Переключить файл
|
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
|
||||||
<kbd>d</kbd>: Отменить изменения коммита в этом файле
|
| `` c `` | Переключить | Переключить файл |
|
||||||
<kbd>o</kbd>: Открыть файл
|
| `` d `` | Remove | Отменить изменения коммита в этом файле |
|
||||||
<kbd>e</kbd>: Редактировать файл
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
<kbd><space></kbd>: Переключить файлы включённые в патч
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Переключить все файлы, включённые в патч
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения)
|
| `` <space> `` | Переключить файлы включённые в патч | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: Переключить вид дерева файлов
|
| `` a `` | Переключить все файлы, включённые в патч | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: Найти
|
| `` <enter> `` | Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: Открыть файл конфигурации
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: Редактировать файл конфигурации
|
| `` o `` | Открыть файл конфигурации | Open file in default application. |
|
||||||
<kbd>u</kbd>: Проверить обновления
|
| `` e `` | Редактировать файл конфигурации | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: Переключиться на последний репозиторий
|
| `` u `` | Проверить обновления | |
|
||||||
<kbd>a</kbd>: Показать все логи ветки
|
| `` <enter> `` | Переключиться на последний репозиторий | |
|
||||||
</pre>
|
| `` a `` | Показать все логи ветки | |
|
||||||
|
|
||||||
## Теги
|
## Теги
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Переключить
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Удалить тег
|
| `` <space> `` | Переключить | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: Отправить тег
|
| `` n `` | Создать тег | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: Создать тег
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` P `` | Отправить тег | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Удалённые ветки
|
## Удалённые ветки
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать название ветки в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: Переключить
|
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
|
||||||
<kbd>n</kbd>: Новая ветка
|
| `` <space> `` | Переключить | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: Слияние с текущей переключённой веткой
|
| `` n `` | Новая ветка | |
|
||||||
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
|
| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: Удалить ветку
|
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
| `` u `` | Set as upstream | Установить как upstream-ветку переключённую ветку |
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
| `` s `` | Порядок сортировки | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Удалённые репозитории
|
## Удалённые репозитории
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: Получение изменения из удалённого репозитория
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: Добавить новую удалённую ветку
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: Удалить удалённую ветку
|
| `` n `` | Добавить новую удалённую ветку | |
|
||||||
<kbd>e</kbd>: Редактировать удалённый репозитории
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | Редактировать удалённый репозитории |
|
||||||
</pre>
|
| `` f `` | Получить изменения | Получение изменения из удалённого репозитория |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## Файлы
|
## Файлы
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: Скопировать название файла в буфер обмена
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: Просмотреть параметры «отмены изменении»
|
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
|
||||||
<kbd><space></kbd>: Переключить индекс
|
| `` <space> `` | Переключить индекс | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: Фильтровать файлы (проиндексированные/непроиндексированные)
|
| `` <c-b> `` | Фильтровать файлы (проиндексированные/непроиндексированные) | |
|
||||||
<kbd>c</kbd>: Сохранить изменения
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
|
| `` c `` | Сохранить изменения | Commit staged changes. |
|
||||||
<kbd>A</kbd>: Правка последнего коммита
|
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
|
||||||
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
|
| `` A `` | Правка последнего коммита | |
|
||||||
<kbd>e</kbd>: Редактировать файл
|
| `` C `` | Сохранить изменения с помощью редактора git | |
|
||||||
<kbd>o</kbd>: Открыть файл
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: Игнорировать или исключить файл
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: Обновить файлы
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
<kbd>s</kbd>: Припрятать все изменения
|
| `` i `` | Игнорировать или исключить файл | |
|
||||||
<kbd>S</kbd>: Просмотреть параметры хранилища
|
| `` r `` | Обновить файлы | |
|
||||||
<kbd>a</kbd>: Все проиндексированные/непроиндексированные
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: Проиндексировать отдельные части/строки для файла или свернуть/развернуть для каталога
|
| `` S `` | Просмотреть параметры хранилища | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса upstream-ветки
|
| `` a `` | Все проиндексированные/непроиндексированные | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: Просмотреть параметры сброса
|
| `` <enter> `` | Проиндексировать отдельные части/строки для файла или свернуть/развернуть для каталога | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: Переключить вид дерева файлов
|
| `` d `` | Просмотреть параметры «отмены изменении» | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
|
| `` g `` | Просмотреть параметры сброса upstream-ветки | |
|
||||||
<kbd>f</kbd>: Получить изменения
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: Найти
|
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
||||||
|
| `` f `` | Получить изменения | Fetch changes from remote. |
|
||||||
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Хранилище
|
## Хранилище
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: Применить припрятанные изменения
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: Применить припрятанные изменения и тут же удалить их из хранилища
|
| `` <space> `` | Применить припрятанные изменения | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: Удалить припрятанные изменения из хранилища
|
| `` g `` | Применить припрятанные изменения и тут же удалить их из хранилища | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: Новая ветка
|
| `` d `` | Удалить припрятанные изменения из хранилища | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Переименовать хранилище
|
| `` n `` | Новая ветка | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
| `` r `` | Переименовать хранилище | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit 按键绑定
|
# Lazygit 按键绑定
|
||||||
|
|
||||||
@@ -6,328 +6,364 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
## 全局键绑定
|
## 全局键绑定
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: 切换到最近的仓库
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: 向上滚动主面板 (fn+up/shift+k)
|
| `` <c-r> `` | 切换到最近的仓库 | |
|
||||||
<kbd><pgdown></kbd>: 向下滚动主面板 (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
|
||||||
<kbd>@</kbd>: 打开命令日志菜单
|
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
|
||||||
<kbd>}</kbd>: 扩大差异视图中显示的上下文范围
|
| `` @ `` | 打开命令日志菜单 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: 缩小差异视图中显示的上下文范围
|
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: 执行自定义命令
|
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: 查看自定义补丁选项
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: 查看 合并/变基 选项
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: 刷新
|
| `` } `` | 扩大差异视图中显示的上下文范围 | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: 下一屏模式(正常/半屏/全屏)
|
| `` { `` | 缩小差异视图中显示的上下文范围 | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: 上一屏模式
|
| `` : `` | 执行自定义命令 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: 打开菜单
|
| `` <c-p> `` | 查看自定义补丁选项 | |
|
||||||
<kbd><c-s></kbd>: 查看按路径过滤选项
|
| `` m `` | 查看 合并/变基 选项 | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: 打开 diff 菜单
|
| `` R `` | 刷新 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: 打开 diff 菜单
|
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||||
<kbd><c-w></kbd>: 切换是否在差异视图中显示空白字符差异
|
| `` _ `` | 上一屏模式 | |
|
||||||
<kbd>z</kbd>: (通过 reflog)撤销「实验功能」
|
| `` ? `` | 打开菜单 | |
|
||||||
<kbd><c-z></kbd>: (通过 reflog)重做「实验功能」
|
| `` <c-s> `` | 查看按路径过滤选项 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: 推送
|
| `` W `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: 拉取
|
| `` <c-e> `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | 退出 | |
|
||||||
|
| `` <esc> `` | 取消 | |
|
||||||
|
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | (通过 reflog)撤销「实验功能」 | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
| `` <c-z> `` | (通过 reflog)重做「实验功能」 | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||||
|
|
||||||
## 列表面板导航
|
## 列表面板导航
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: 上一页
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: 下一页
|
| `` , `` | 上一页 | |
|
||||||
<kbd><</kbd>: 滚动到顶部
|
| `` . `` | 下一页 | |
|
||||||
<kbd>></kbd>: 滚动到底部
|
| `` < `` | 滚动到顶部 | |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` > `` | 滚动到底部 | |
|
||||||
<kbd>H</kbd>: 向左滚动
|
| `` v `` | 切换拖动选择 | |
|
||||||
<kbd>L</kbd>: 向右滚动
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: 下一个标签
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: 上一个标签
|
| `` / `` | 开始搜索 | |
|
||||||
</pre>
|
| `` H `` | 向左滚动 | |
|
||||||
|
| `` L `` | 向右滚动 | |
|
||||||
|
| `` ] `` | 下一个标签 | |
|
||||||
|
| `` [ `` | 上一个标签 | |
|
||||||
|
|
||||||
## Reflog 页面
|
## Reflog 页面
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将提交的 SHA 复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 检出提交
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: 在浏览器中打开提交
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: 从提交创建新分支
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` n `` | 从提交创建新分支 | |
|
||||||
<kbd>c</kbd>: 复制提交(拣选)
|
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
<kbd><enter></kbd>: 查看提交
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | 查看提交 | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 分支页面
|
## 分支页面
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将分支名称复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: 显示 git-flow 选项
|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||||
<kbd><space></kbd>: 检出
|
| `` i `` | 显示 git-flow 选项 | |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` <space> `` | 检出 | Checkout selected item. |
|
||||||
<kbd>o</kbd>: 创建抓取请求
|
| `` n `` | 新分支 | |
|
||||||
<kbd>O</kbd>: 创建抓取请求选项
|
| `` o `` | 创建抓取请求 | |
|
||||||
<kbd><c-y></kbd>: 将抓取请求 URL 复制到剪贴板
|
| `` O `` | 创建抓取请求选项 | |
|
||||||
<kbd>c</kbd>: 按名称检出
|
| `` <c-y> `` | 将抓取请求 URL 复制到剪贴板 | |
|
||||||
<kbd>F</kbd>: 强制检出
|
| `` c `` | 按名称检出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: 删除分支
|
| `` F `` | 强制检出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: 将已检出的分支变基到该分支
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: 合并到当前检出的分支
|
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: 从上游快进此分支
|
| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: 创建标签
|
| `` f `` | 从上游快进此分支 | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` T `` | 创建标签 | |
|
||||||
<kbd>R</kbd>: 重命名分支
|
| `` s `` | Sort order | |
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
| `` g `` | 查看重置选项 | |
|
||||||
<kbd><enter></kbd>: 查看提交
|
| `` R `` | 重命名分支 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 查看提交 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将提交的 SHA 复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 检出提交
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: 在浏览器中打开提交
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: 从提交创建新分支
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` n `` | 从提交创建新分支 | |
|
||||||
<kbd>c</kbd>: 复制提交(拣选)
|
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 子模块
|
## 子模块
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将子模块名称复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: 输入子模块
|
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
|
||||||
<kbd>d</kbd>: 删除子模块
|
| `` <enter> `` | Enter | 输入子模块 |
|
||||||
<kbd>u</kbd>: 更新子模块
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: 添加新的子模块
|
| `` u `` | Update | 更新子模块 |
|
||||||
<kbd>e</kbd>: 更新子模块 URL
|
| `` n `` | 添加新的子模块 | |
|
||||||
<kbd>i</kbd>: 初始化子模块
|
| `` e `` | 更新子模块 URL | |
|
||||||
<kbd>b</kbd>: 查看批量子模块选项
|
| `` i `` | Initialize | 初始化子模块 |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | 查看批量子模块选项 | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将提交的 SHA 复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
<kbd>b</kbd>: 查看二分查找选项
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
<kbd>s</kbd>: 向下压缩
|
| `` b `` | 查看二分查找选项 | |
|
||||||
<kbd>f</kbd>: 修正提交(fixup)
|
| `` s `` | 压缩 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: 改写提交
|
| `` f `` | 修正(fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: 使用编辑器重命名提交
|
| `` r `` | 改写提交 | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: 删除提交
|
| `` R `` | 使用编辑器重命名提交 | |
|
||||||
<kbd>e</kbd>: 编辑提交
|
| `` d `` | 删除提交 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: 选择提交(变基过程中)
|
| `` e `` | Edit (start interactive rebase) | 编辑提交 |
|
||||||
<kbd>F</kbd>: 创建修正提交
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: 压缩在所选提交之上的所有“fixup!”提交(自动压缩)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: 下移提交
|
| `` p `` | Pick | 选择提交(变基过程中) |
|
||||||
<kbd><c-k></kbd>: 上移提交
|
| `` F `` | 为此提交创建修正 | 创建修正提交 |
|
||||||
<kbd>v</kbd>: 粘贴提交(拣选)
|
| `` S `` | Apply fixup commits | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
|
||||||
<kbd>A</kbd>: 用已暂存的更改来修补提交
|
| `` <c-j> `` | 下移提交 | |
|
||||||
<kbd>a</kbd>: Set/Reset commit author
|
| `` <c-k> `` | 上移提交 | |
|
||||||
<kbd>t</kbd>: 还原提交
|
| `` V `` | 粘贴提交(拣选) | |
|
||||||
<kbd>T</kbd>: 标签提交
|
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||||
<kbd><c-l></kbd>: 打开日志菜单
|
| `` A `` | Amend | 用已暂存的更改来修补提交 |
|
||||||
<kbd><space></kbd>: 检出提交
|
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: Copy commit attribute
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: 在浏览器中打开提交
|
| `` T `` | 标签提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 从提交创建新分支
|
| `` <c-l> `` | 打开日志菜单 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: 复制提交(拣选)
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
| `` n `` | 从提交创建新分支 | |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 提交文件
|
## 提交文件
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将提交的文件名复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: 检出文件
|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||||
<kbd>d</kbd>: 放弃对此文件的提交更改
|
| `` c `` | 检出 | 检出文件 |
|
||||||
<kbd>o</kbd>: 打开文件
|
| `` d `` | Remove | 放弃对此文件的提交更改 |
|
||||||
<kbd>e</kbd>: 编辑文件
|
| `` o `` | 打开文件 | Open file in default application. |
|
||||||
<kbd><space></kbd>: 补丁中包含的切换文件
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: Toggle all files included in patch
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: 输入文件以将所选行添加到补丁中(或切换目录折叠)
|
| `` <space> `` | 补丁中包含的切换文件 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: 切换文件树视图
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 提交讯息
|
## 提交讯息
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 确认
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 关闭
|
| `` <enter> `` | 确认 | |
|
||||||
</pre>
|
| `` <esc> `` | 关闭 | |
|
||||||
|
|
||||||
## 文件
|
## 文件
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将文件名复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: 查看'放弃更改'选项
|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||||
<kbd><space></kbd>: 切换暂存状态
|
| `` <space> `` | 切换暂存状态 | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: Filter files by status
|
| `` <c-b> `` | Filter files by status | |
|
||||||
<kbd>c</kbd>: 提交更改
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
| `` c `` | 提交更改 | Commit staged changes. |
|
||||||
<kbd>A</kbd>: 修补最后一次提交
|
| `` w `` | 提交更改而无需预先提交钩子 | |
|
||||||
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
|
| `` A `` | 修补最后一次提交 | |
|
||||||
<kbd>e</kbd>: 编辑文件
|
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
||||||
<kbd>o</kbd>: 打开文件
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: 忽略文件
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: 刷新文件
|
| `` o `` | 打开文件 | Open file in default application. |
|
||||||
<kbd>s</kbd>: 将所有更改加入贮藏
|
| `` i `` | 忽略文件 | |
|
||||||
<kbd>S</kbd>: 查看贮藏选项
|
| `` r `` | 刷新文件 | |
|
||||||
<kbd>a</kbd>: 切换所有文件的暂存状态
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: 暂存单个 块/行 用于文件, 或 折叠/展开 目录
|
| `` S `` | 查看贮藏选项 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: 查看上游重置选项
|
| `` a `` | 切换所有文件的暂存状态 | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: 查看重置选项
|
| `` <enter> `` | 暂存单个 块/行 用于文件, 或 折叠/展开 目录 | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: 切换文件树视图
|
| `` d `` | 查看'放弃更改'选项 | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
|
| `` g `` | 查看上游重置选项 | |
|
||||||
<kbd>f</kbd>: 抓取
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
||||||
|
| `` f `` | 抓取 | Fetch changes from remote. |
|
||||||
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 构建补丁中
|
## 构建补丁中
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 选择上一个区块
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 选择下一个区块
|
| `` <left> `` | 选择上一个区块 | |
|
||||||
<kbd>v</kbd>: 切换拖动选择
|
| `` <right> `` | 选择下一个区块 | |
|
||||||
<kbd>V</kbd>: 切换拖动选择
|
| `` v `` | 切换拖动选择 | |
|
||||||
<kbd>a</kbd>: 切换选择区块
|
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 将选中文本复制到剪贴板
|
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||||
<kbd>o</kbd>: 打开文件
|
| `` o `` | 打开文件 | Open file in default application. |
|
||||||
<kbd>e</kbd>: 编辑文件
|
| `` e `` | 编辑文件 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 添加/移除 行到补丁
|
| `` <space> `` | 添加/移除 行到补丁 | |
|
||||||
<kbd><esc></kbd>: 退出逐行模式
|
| `` <esc> `` | 退出逐行模式 | |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` / `` | 开始搜索 | |
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 标签页面
|
## 标签页面
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 检出
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: 删除标签
|
| `` <space> `` | 检出 | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: 推送标签
|
| `` n `` | 创建标签 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 创建标签
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` P `` | 推送标签 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: 查看提交
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | 查看提交 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 正在合并
|
## 正在合并
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>e</kbd>: 编辑文件
|
|-----|--------|-------------|
|
||||||
<kbd>o</kbd>: 打开文件
|
| `` <space> `` | 选中区块 | |
|
||||||
<kbd><left></kbd>: 选择上一个冲突
|
| `` b `` | 选中所有区块 | |
|
||||||
<kbd><right></kbd>: 选择下一个冲突
|
| `` <up> `` | 选择顶部块 | |
|
||||||
<kbd><up></kbd>: 选择顶部块
|
| `` <down> `` | 选择底部块 | |
|
||||||
<kbd><down></kbd>: 选择底部块
|
| `` <left> `` | 选择上一个冲突 | |
|
||||||
<kbd>z</kbd>: 撤销
|
| `` <right> `` | 选择下一个冲突 | |
|
||||||
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
|
| `` z `` | 撤销 | Undo last merge conflict resolution. |
|
||||||
<kbd><space></kbd>: 选中区块
|
| `` e `` | 编辑文件 | Open file in external editor. |
|
||||||
<kbd>b</kbd>: 选中所有区块
|
| `` o `` | 打开文件 | Open file in default application. |
|
||||||
<kbd><esc></kbd>: 返回文件面板
|
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
||||||
</pre>
|
| `` <esc> `` | 返回文件面板 | |
|
||||||
|
|
||||||
## 正在暂存
|
## 正在暂存
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 选择上一个区块
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 选择下一个区块
|
| `` <left> `` | 选择上一个区块 | |
|
||||||
<kbd>v</kbd>: 切换拖动选择
|
| `` <right> `` | 选择下一个区块 | |
|
||||||
<kbd>V</kbd>: 切换拖动选择
|
| `` v `` | 切换拖动选择 | |
|
||||||
<kbd>a</kbd>: 切换选择区块
|
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 将选中文本复制到剪贴板
|
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||||
<kbd>o</kbd>: 打开文件
|
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
|
||||||
<kbd>e</kbd>: 编辑文件
|
| `` d `` | 取消变更 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
<kbd><esc></kbd>: 返回文件面板
|
| `` o `` | 打开文件 | Open file in default application. |
|
||||||
<kbd><tab></kbd>: 切换到其他面板
|
| `` e `` | 编辑文件 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 切换行暂存状态
|
| `` <esc> `` | 返回文件面板 | |
|
||||||
<kbd>d</kbd>: 取消变更 (git reset)
|
| `` <tab> `` | 切换到其他面板 | Switch to other view (staged/unstaged changes). |
|
||||||
<kbd>E</kbd>: Edit hunk
|
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||||
<kbd>c</kbd>: 提交更改
|
| `` c `` | 提交更改 | Commit staged changes. |
|
||||||
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
| `` w `` | 提交更改而无需预先提交钩子 | |
|
||||||
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
|
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
||||||
<kbd>/</kbd>: 开始搜索
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
</pre>
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 正常
|
## 正常
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>mouse wheel down</kbd>: 向下滚动 (fn+up)
|
|-----|--------|-------------|
|
||||||
<kbd>mouse wheel up</kbd>: 向上滚动 (fn+down)
|
| `` mouse wheel down (fn+up) `` | 向下滚动 | |
|
||||||
</pre>
|
| `` mouse wheel up (fn+down) `` | 向上滚动 | |
|
||||||
|
|
||||||
## 状态
|
## 状态
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: 打开配置文件
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: 编辑配置文件
|
| `` o `` | 打开配置文件 | Open file in default application. |
|
||||||
<kbd>u</kbd>: 检查更新
|
| `` e `` | 编辑配置文件 | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: 切换到最近的仓库
|
| `` u `` | 检查更新 | |
|
||||||
<kbd>a</kbd>: 显示所有分支的日志
|
| `` <enter> `` | 切换到最近的仓库 | |
|
||||||
</pre>
|
| `` a `` | 显示所有分支的日志 | |
|
||||||
|
|
||||||
## 确认面板
|
## 确认面板
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 确认
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 关闭
|
| `` <enter> `` | 确认 | |
|
||||||
</pre>
|
| `` <esc> `` | 关闭 | |
|
||||||
|
|
||||||
## 菜单
|
## 菜单
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 执行
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 关闭
|
| `` <enter> `` | 执行 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | 关闭 | |
|
||||||
</pre>
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 贮藏
|
## 贮藏
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 应用
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: 应用并删除
|
| `` <space> `` | 应用 | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: 删除
|
| `` g `` | 应用并删除 | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` d `` | 删除 | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: Rename stash
|
| `` n `` | 新分支 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
| `` r `` | Rename stash | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
</pre>
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 远程分支
|
## 远程分支
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 将分支名称复制到剪贴板
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 检出
|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` <space> `` | 检出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: 合并到当前检出的分支
|
| `` n `` | 新分支 | |
|
||||||
<kbd>r</kbd>: 将已检出的分支变基到该分支
|
| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: 删除分支
|
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: 设置为检出分支的上游
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: 查看重置选项
|
| `` u `` | Set as upstream | 设置为检出分支的上游 |
|
||||||
<kbd><enter></kbd>: 查看提交
|
| `` s `` | Sort order | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 查看提交 | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
## 远程页面
|
## 远程页面
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: 抓取远程仓库
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: 添加新的远程仓库
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: 删除远程
|
| `` n `` | 添加新的远程仓库 | |
|
||||||
<kbd>e</kbd>: 编辑远程仓库
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | 编辑远程仓库 |
|
||||||
</pre>
|
| `` f `` | 抓取 | 抓取远程仓库 |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
@@ -1,333 +1,369 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
|
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||||
|
|
||||||
# Lazygit 鍵盤快捷鍵
|
# Lazygit 鍵盤快捷鍵
|
||||||
|
|
||||||
_說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
_說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
||||||
|
|
||||||
## 全局快捷鍵
|
## 全域快捷鍵
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-r></kbd>: 切換到最近使用的版本庫
|
|-----|--------|-------------|
|
||||||
<kbd><pgup></kbd>: 向上捲動主面板 (fn+up/shift+k)
|
| `` <c-r> `` | 切換到最近使用的版本庫 | |
|
||||||
<kbd><pgdown></kbd>: 向下捲動主面板 (fn+down/shift+j)
|
| `` <pgup> (fn+up/shift+k) `` | 向上捲動主面板 | |
|
||||||
<kbd>@</kbd>: 開啟命令記錄選單
|
| `` <pgdown> (fn+down/shift+j) `` | 向下捲動主面板 | |
|
||||||
<kbd>}</kbd>: 增加差異檢視中顯示變更周圍上下文的大小
|
| `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
<kbd>{</kbd>: 減小差異檢視中顯示變更周圍上下文的大小
|
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd>:</kbd>: 執行自訂命令
|
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
<kbd><c-p></kbd>: 檢視自訂補丁選項
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>m</kbd>: 查看合併/變基選項
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
<kbd>R</kbd>: 重新整理
|
| `` } `` | 增加差異檢視中顯示變更周圍上下文的大小 | Increase the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>+</kbd>: 下一個螢幕模式(常規/半螢幕/全螢幕)
|
| `` { `` | 減小差異檢視中顯示變更周圍上下文的大小 | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
<kbd>_</kbd>: 上一個螢幕模式
|
| `` : `` | 執行自訂命令 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
||||||
<kbd>?</kbd>: 開啟選單
|
| `` <c-p> `` | 檢視自訂補丁選項 | |
|
||||||
<kbd><c-s></kbd>: 檢視篩選路徑選項
|
| `` m `` | 查看合併/變基選項 | View options to abort/continue/skip the current merge/rebase. |
|
||||||
<kbd>W</kbd>: 開啟差異比較選單
|
| `` R `` | 重新整理 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||||
<kbd><c-e></kbd>: 開啟差異比較選單
|
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
|
||||||
<kbd><c-w></kbd>: 切換是否在差異檢視中顯示空格變更
|
| `` _ `` | 上一個螢幕模式 | |
|
||||||
<kbd>z</kbd>: 復原
|
| `` ? `` | 開啟選單 | |
|
||||||
<kbd><c-z></kbd>: 取消復原
|
| `` <c-s> `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
<kbd>P</kbd>: 推送
|
| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
<kbd>p</kbd>: 拉取
|
| `` <c-e> `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
</pre>
|
| `` q `` | 結束 | |
|
||||||
|
| `` <esc> `` | 取消 | |
|
||||||
|
| `` <c-w> `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | 復原 | 將使用 reflog 確任 git 指令以復原。這不包括工作區更改;只考慮提交。 |
|
||||||
|
| `` <c-z> `` | 取消復原 | 將使用 reflog 確任 git 指令以重作。這不包括工作區更改;只考慮提交。 |
|
||||||
|
|
||||||
## 列表面板導航
|
## 移動
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>,</kbd>: 上一頁
|
|-----|--------|-------------|
|
||||||
<kbd>.</kbd>: 下一頁
|
| `` , `` | 上一頁 | |
|
||||||
<kbd><</kbd>: 捲動到頂部
|
| `` . `` | 下一頁 | |
|
||||||
<kbd>></kbd>: 捲動到底部
|
| `` < `` | 捲動到頂部 | |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` > `` | 捲動到底部 | |
|
||||||
<kbd>H</kbd>: 向左捲動
|
| `` v `` | 切換拖曳選擇 | |
|
||||||
<kbd>L</kbd>: 向右捲動
|
| `` <s-down> `` | Range select down | |
|
||||||
<kbd>]</kbd>: 下一個索引標籤
|
| `` <s-up> `` | Range select up | |
|
||||||
<kbd>[</kbd>: 上一個索引標籤
|
| `` / `` | 搜尋 | |
|
||||||
</pre>
|
| `` H `` | 向左捲動 | |
|
||||||
|
| `` L `` | 向右捲動 | |
|
||||||
## Reflog
|
| `` ] `` | 下一個索引標籤 | |
|
||||||
|
| `` [ `` | 上一個索引標籤 | |
|
||||||
<pre>
|
|
||||||
<kbd><c-o></kbd>: 複製提交 SHA 到剪貼簿
|
|
||||||
<kbd><space></kbd>: 檢出提交
|
|
||||||
<kbd>y</kbd>: 複製提交屬性
|
|
||||||
<kbd>o</kbd>: 在瀏覽器中開啟提交
|
|
||||||
<kbd>n</kbd>: 從提交建立新分支
|
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
|
||||||
<kbd>c</kbd>: 複製提交 (揀選)
|
|
||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
|
||||||
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
|
||||||
<kbd><enter></kbd>: 檢視提交
|
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 主視窗 (一般)
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd>mouse wheel down</kbd>: 向下捲動 (fn+up)
|
|
||||||
<kbd>mouse wheel up</kbd>: 向上捲動 (fn+down)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 主視窗 (合併中)
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd>e</kbd>: 編輯檔案
|
|
||||||
<kbd>o</kbd>: 開啟檔案
|
|
||||||
<kbd><left></kbd>: 選擇上一個衝突
|
|
||||||
<kbd><right></kbd>: 選擇下一個衝突
|
|
||||||
<kbd><up></kbd>: 選擇上一段
|
|
||||||
<kbd><down></kbd>: 選擇下一段
|
|
||||||
<kbd>z</kbd>: 復原
|
|
||||||
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
|
|
||||||
<kbd><space></kbd>: 挑選程式碼片段
|
|
||||||
<kbd>b</kbd>: 挑選所有程式碼片段
|
|
||||||
<kbd><esc></kbd>: 返回檔案面板
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 主視窗 (預存中)
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<kbd><left></kbd>: 選擇上一段
|
|
||||||
<kbd><right></kbd>: 選擇下一段
|
|
||||||
<kbd>v</kbd>: 切換拖曳選擇
|
|
||||||
<kbd>V</kbd>: 切換拖曳選擇
|
|
||||||
<kbd>a</kbd>: 切換選擇程式碼塊
|
|
||||||
<kbd><c-o></kbd>: 複製所選文本至剪貼簿
|
|
||||||
<kbd>o</kbd>: 開啟檔案
|
|
||||||
<kbd>e</kbd>: 編輯檔案
|
|
||||||
<kbd><esc></kbd>: 返回檔案面板
|
|
||||||
<kbd><tab></kbd>: 切換至另一個面板 (已預存/未預存更改)
|
|
||||||
<kbd><space></kbd>: 切換現有行的狀態 (已預存/未預存)
|
|
||||||
<kbd>d</kbd>: 刪除變更 (git reset)
|
|
||||||
<kbd>E</kbd>: 編輯程式碼塊
|
|
||||||
<kbd>c</kbd>: 提交變更
|
|
||||||
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
|
|
||||||
<kbd>C</kbd>: 使用 git 編輯器提交變更
|
|
||||||
<kbd>/</kbd>: 開始搜尋
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
## 主面板 (補丁生成)
|
## 主面板 (補丁生成)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><left></kbd>: 選擇上一段
|
|-----|--------|-------------|
|
||||||
<kbd><right></kbd>: 選擇下一段
|
| `` <left> `` | 選擇上一段 | |
|
||||||
<kbd>v</kbd>: 切換拖曳選擇
|
| `` <right> `` | 選擇下一段 | |
|
||||||
<kbd>V</kbd>: 切換拖曳選擇
|
| `` v `` | 切換拖曳選擇 | |
|
||||||
<kbd>a</kbd>: 切換選擇程式碼塊
|
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
|
||||||
<kbd><c-o></kbd>: 複製所選文本至剪貼簿
|
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
|
||||||
<kbd>o</kbd>: 開啟檔案
|
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||||
<kbd>e</kbd>: 編輯檔案
|
| `` e `` | 編輯檔案 | Open file in external editor. |
|
||||||
<kbd><space></kbd>: 向 (或從) 補丁中添加/刪除行
|
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
|
||||||
<kbd><esc></kbd>: 退出自訂補丁建立器
|
| `` <esc> `` | 退出自訂補丁建立器 | |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` / `` | 搜尋 | |
|
||||||
</pre>
|
|
||||||
|
## 主面板(一般)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` mouse wheel down (fn+up) `` | 向下捲動 | |
|
||||||
|
| `` mouse wheel up (fn+down) `` | 向上捲動 | |
|
||||||
|
|
||||||
|
## 主面板(合併)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <space> `` | 挑選程式碼片段 | |
|
||||||
|
| `` b `` | 挑選所有程式碼片段 | |
|
||||||
|
| `` <up> `` | 選擇上一段 | |
|
||||||
|
| `` <down> `` | 選擇下一段 | |
|
||||||
|
| `` <left> `` | 選擇上一個衝突 | |
|
||||||
|
| `` <right> `` | 選擇下一個衝突 | |
|
||||||
|
| `` z `` | 復原 | Undo last merge conflict resolution. |
|
||||||
|
| `` e `` | 編輯檔案 | Open file in external editor. |
|
||||||
|
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||||
|
| `` M `` | 開啟外部合併工具 (git mergetool) | Run `git mergetool`. |
|
||||||
|
| `` <esc> `` | 返回檔案面板 | |
|
||||||
|
|
||||||
|
## 主面板(預存)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <left> `` | 選擇上一段 | |
|
||||||
|
| `` <right> `` | 選擇下一段 | |
|
||||||
|
| `` v `` | 切換拖曳選擇 | |
|
||||||
|
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
|
||||||
|
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
|
||||||
|
| `` <space> `` | 切換預存 | 切換現有行的狀態 (已預存/未預存) |
|
||||||
|
| `` d `` | 刪除變更 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||||
|
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||||
|
| `` e `` | 編輯檔案 | Open file in external editor. |
|
||||||
|
| `` <esc> `` | 返回檔案面板 | |
|
||||||
|
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | Switch to other view (staged/unstaged changes). |
|
||||||
|
| `` E `` | 編輯程式碼塊 | Edit selected hunk in external editor. |
|
||||||
|
| `` c `` | 提交變更 | Commit staged changes. |
|
||||||
|
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
||||||
|
| `` C `` | 使用 git 編輯器提交變更 | |
|
||||||
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 功能表
|
## 功能表
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 執行
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 關閉
|
| `` <enter> `` | 執行 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <esc> `` | 關閉 | |
|
||||||
</pre>
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製提交 SHA 到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 檢出提交
|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
|
||||||
<kbd>y</kbd>: 複製提交屬性
|
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>o</kbd>: 在瀏覽器中開啟提交
|
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>n</kbd>: 從提交建立新分支
|
| `` o `` | 在瀏覽器中開啟提交 | |
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
| `` n `` | 從提交建立新分支 | |
|
||||||
<kbd>c</kbd>: 複製提交 (揀選)
|
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
</pre>
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 子模組
|
## 子模組
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製子模組名稱到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd><enter></kbd>: 進入子模組
|
| `` <c-o> `` | 複製子模組名稱到剪貼簿 | |
|
||||||
<kbd>d</kbd>: 移除子模組
|
| `` <enter> `` | Enter | 進入子模組 |
|
||||||
<kbd>u</kbd>: 更新子模組
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
<kbd>n</kbd>: 新增子模組
|
| `` u `` | Update | 更新子模組 |
|
||||||
<kbd>e</kbd>: 更新子模組 URL
|
| `` n `` | 新增子模組 | |
|
||||||
<kbd>i</kbd>: 初始化子模組
|
| `` e `` | 更新子模組 URL | |
|
||||||
<kbd>b</kbd>: 查看批量子模組選項
|
| `` i `` | Initialize | 初始化子模組 |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` b `` | 查看批量子模組選項 | |
|
||||||
</pre>
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
|
## 工作目錄
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Open in editor | |
|
||||||
|
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製提交 SHA 到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
|
||||||
<kbd>b</kbd>: 查看二分選項
|
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||||
<kbd>s</kbd>: 向下壓縮
|
| `` b `` | 查看二分選項 | |
|
||||||
<kbd>f</kbd>: 修復提交 (Fixup)
|
| `` s `` | 壓縮 (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
<kbd>r</kbd>: 改寫提交
|
| `` f `` | 修復 (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
<kbd>R</kbd>: 使用編輯器改寫提交
|
| `` r `` | 改寫提交 | Reword the selected commit's message. |
|
||||||
<kbd>d</kbd>: 刪除提交
|
| `` R `` | 使用編輯器改寫提交 | |
|
||||||
<kbd>e</kbd>: 編輯提交
|
| `` d `` | 刪除提交 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||||
<kbd>p</kbd>: 挑選提交 (於變基過程中)
|
| `` e `` | Edit (start interactive rebase) | 編輯提交 |
|
||||||
<kbd>F</kbd>: 為此提交建立修復提交
|
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||||
<kbd>S</kbd>: 壓縮上方所有的“fixup!”提交 (自動壓縮)
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
<kbd><c-j></kbd>: 向下移動提交
|
| `` p `` | Pick | 挑選提交 (於變基過程中) |
|
||||||
<kbd><c-k></kbd>: 向上移動提交
|
| `` F `` | 建立修復提交 | 為此提交建立修復提交 |
|
||||||
<kbd>v</kbd>: 貼上提交 (揀選)
|
| `` S `` | 壓縮上方所有「fixup」提交(自動壓縮) | 是否壓縮上方 {{.commit}} 所有「fixup」提交? |
|
||||||
<kbd>A</kbd>: 使用已預存的更改修正提交
|
| `` <c-j> `` | 向下移動提交 | |
|
||||||
<kbd>a</kbd>: 設置/重設提交作者
|
| `` <c-k> `` | 向上移動提交 | |
|
||||||
<kbd>t</kbd>: 還原提交
|
| `` V `` | 貼上提交 (揀選) | |
|
||||||
<kbd>T</kbd>: 打標籤到提交
|
| `` B `` | 為了變基已標注提交為基準提交 | 請為了下一次變基選擇一項基準提交;此將執行 `git rebase --onto`。 |
|
||||||
<kbd><c-l></kbd>: 開啟記錄選單
|
| `` A `` | Amend | 使用已預存的更改修正提交 |
|
||||||
<kbd><space></kbd>: 檢出提交
|
| `` a `` | 設定/重設提交作者 | Set/Reset commit author or set co-author. |
|
||||||
<kbd>y</kbd>: 複製提交屬性
|
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
<kbd>o</kbd>: 在瀏覽器中開啟提交
|
| `` T `` | 打標籤到提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 從提交建立新分支
|
| `` <c-l> `` | 開啟記錄選單 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
||||||
<kbd>c</kbd>: 複製提交 (揀選)
|
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
| `` o `` | 在瀏覽器中開啟提交 | |
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
| `` n `` | 從提交建立新分支 | |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 提交摘要
|
## 提交摘要
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 確認
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 關閉
|
| `` <enter> `` | 確認 | |
|
||||||
</pre>
|
| `` <esc> `` | 關閉 | |
|
||||||
|
|
||||||
## 提交檔案
|
## 提交檔案
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製提交的檔案名稱到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd>c</kbd>: 檢出檔案
|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||||
<kbd>d</kbd>: 捨棄此提交對此檔案的更改
|
| `` c `` | 檢出 | 檢出檔案 |
|
||||||
<kbd>o</kbd>: 開啟檔案
|
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
|
||||||
<kbd>e</kbd>: 編輯檔案
|
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||||
<kbd><space></kbd>: 切換檔案是否包含在補丁中
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>a</kbd>: 切換所有檔案是否包含在補丁中
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
<kbd><enter></kbd>: 輸入檔案以將選定的行添加至補丁(或切換目錄折疊)
|
| `` <space> `` | 切換檔案是否包含在補丁中 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>`</kbd>: 切換檔案樹狀視圖
|
| `` a `` | 切換所有檔案是否包含在補丁中 | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` <enter> `` | 輸入檔案以將選定的行添加至補丁(或切換目錄折疊) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||||
</pre>
|
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 收藏 (Stash)
|
## 收藏 (Stash)
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 套用
|
|-----|--------|-------------|
|
||||||
<kbd>g</kbd>: 還原
|
| `` <space> `` | 套用 | Apply the stash entry to your working directory. |
|
||||||
<kbd>d</kbd>: 捨棄
|
| `` g `` | 還原 | Apply the stash entry to your working directory and remove the stash entry. |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` d `` | 捨棄 | Remove the stash entry from the stash list. |
|
||||||
<kbd>r</kbd>: 重新命名收藏
|
| `` n `` | 新分支 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
| `` r `` | 重新命名收藏 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
</pre>
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
|
## 日誌
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
|
||||||
|
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
||||||
|
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
|
| `` o `` | 在瀏覽器中開啟提交 | |
|
||||||
|
| `` n `` | 從提交建立新分支 | |
|
||||||
|
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||||
|
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 檢視提交 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 本地分支
|
## 本地分支
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製分支名稱到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd>i</kbd>: 顯示 git-flow 選項
|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
||||||
<kbd><space></kbd>: 檢出
|
| `` i `` | 顯示 git-flow 選項 | |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` <space> `` | 檢出 | Checkout selected item. |
|
||||||
<kbd>o</kbd>: 建立拉取請求
|
| `` n `` | 新分支 | |
|
||||||
<kbd>O</kbd>: 建立拉取請求選項
|
| `` o `` | 建立拉取請求 | |
|
||||||
<kbd><c-y></kbd>: 複製拉取請求的 URL 到剪貼板
|
| `` O `` | 建立拉取請求選項 | |
|
||||||
<kbd>c</kbd>: 根據名稱檢出
|
| `` <c-y> `` | 複製拉取請求的 URL 到剪貼板 | |
|
||||||
<kbd>F</kbd>: 強制檢出
|
| `` c `` | 根據名稱檢出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
<kbd>d</kbd>: 刪除分支
|
| `` F `` | 強制檢出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
<kbd>r</kbd>: 將已檢出的分支變基至此分支
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
<kbd>M</kbd>: 合併到當前檢出的分支
|
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>f</kbd>: 從上游快進此分支
|
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>T</kbd>: 建立標籤
|
| `` f `` | 從上游快進此分支 | Fast-forward selected branch from its upstream. |
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
| `` T `` | 建立標籤 | |
|
||||||
<kbd>R</kbd>: 重新命名分支
|
| `` s `` | Sort order | |
|
||||||
<kbd>u</kbd>: 設定/取消設定上游
|
| `` g `` | 檢視重設選項 | |
|
||||||
<kbd><enter></kbd>: 檢視提交
|
| `` R `` | 重新命名分支 | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` u `` | 檢視上游設定 | 檢視有關上游分支的設定(例如重設至上游) |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 檢視提交 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 標籤
|
## 標籤
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><space></kbd>: 檢出
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: 刪除標籤
|
| `` <space> `` | 檢出 | Checkout the selected tag tag as a detached HEAD. |
|
||||||
<kbd>P</kbd>: 推送標籤
|
| `` n `` | 建立標籤 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
<kbd>n</kbd>: 建立標籤
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
<kbd><enter></kbd>: 檢視提交
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
</pre>
|
| `` <enter> `` | 檢視提交 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 檔案
|
## 檔案
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製檔案名稱到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd>d</kbd>: 檢視“捨棄更改”的選項
|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||||
<kbd><space></kbd>: 切換預存
|
| `` <space> `` | 切換預存 | Toggle staged for selected file. |
|
||||||
<kbd><c-b></kbd>: 篩選檔案 (預存/未預存)
|
| `` <c-b> `` | 篩選檔案 (預存/未預存) | |
|
||||||
<kbd>c</kbd>: 提交變更
|
| `` y `` | Copy to clipboard | |
|
||||||
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
|
| `` c `` | 提交變更 | Commit staged changes. |
|
||||||
<kbd>A</kbd>: 修正上次提交
|
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
||||||
<kbd>C</kbd>: 使用 git 編輯器提交變更
|
| `` A `` | 修改上次提交 | |
|
||||||
<kbd>e</kbd>: 編輯檔案
|
| `` C `` | 使用 git 編輯器提交變更 | |
|
||||||
<kbd>o</kbd>: 開啟檔案
|
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
<kbd>i</kbd>: 忽略或排除檔案
|
| `` e `` | Edit | Open file in external editor. |
|
||||||
<kbd>r</kbd>: 重新整理檔案
|
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||||
<kbd>s</kbd>: 收藏所有變更
|
| `` i `` | 忽略或排除檔案 | |
|
||||||
<kbd>S</kbd>: 檢視收藏選項
|
| `` r `` | 重新整理檔案 | |
|
||||||
<kbd>a</kbd>: 全部預存/取消預存
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
<kbd><enter></kbd>: 選擇檔案中的單個程式碼塊/行,或展開/折疊目錄
|
| `` S `` | 檢視收藏選項 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
<kbd>g</kbd>: 檢視上游重設選項
|
| `` a `` | 全部預存/取消預存 | Toggle staged/unstaged for all files in working tree. |
|
||||||
<kbd>D</kbd>: 檢視重設選項
|
| `` <enter> `` | 選擇檔案中的單個程式碼塊/行,或展開/折疊目錄 | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||||
<kbd>`</kbd>: 切換檔案樹狀視圖
|
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||||
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
|
| `` g `` | 檢視上游重設選項 | |
|
||||||
<kbd>f</kbd>: 擷取
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
<kbd>/</kbd>: 開始搜尋
|
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` M `` | 開啟外部合併工具 (git mergetool) | Run `git mergetool`. |
|
||||||
|
| `` f `` | 擷取 | Fetch changes from remote. |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 狀態
|
## 狀態
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>o</kbd>: 開啟設定檔案
|
|-----|--------|-------------|
|
||||||
<kbd>e</kbd>: 編輯設定檔案
|
| `` o `` | 開啟設定檔案 | Open file in default application. |
|
||||||
<kbd>u</kbd>: 檢查更新
|
| `` e `` | 編輯設定檔案 | Open file in external editor. |
|
||||||
<kbd><enter></kbd>: 切換到最近使用的版本庫
|
| `` u `` | 檢查更新 | |
|
||||||
<kbd>a</kbd>: 顯示所有分支日誌
|
| `` <enter> `` | 切換到最近使用的版本庫 | |
|
||||||
</pre>
|
| `` a `` | 顯示所有分支日誌 | |
|
||||||
|
|
||||||
## 確認面板
|
## 確認面板
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><enter></kbd>: 確認
|
|-----|--------|-------------|
|
||||||
<kbd><esc></kbd>: 關閉/取消
|
| `` <enter> `` | 確認 | |
|
||||||
</pre>
|
| `` <esc> `` | 關閉/取消 | |
|
||||||
|
|
||||||
## 遠端
|
## 遠端
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd>f</kbd>: 擷取遠端
|
|-----|--------|-------------|
|
||||||
<kbd>n</kbd>: 新增遠端
|
| `` <enter> `` | View branches | |
|
||||||
<kbd>d</kbd>: 移除遠端
|
| `` n `` | 新增遠端 | |
|
||||||
<kbd>e</kbd>: 編輯遠端
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` e `` | Edit | 編輯遠端 |
|
||||||
</pre>
|
| `` f `` | 擷取 | 擷取遠端 |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 遠端分支
|
## 遠端分支
|
||||||
|
|
||||||
<pre>
|
| Key | Action | Info |
|
||||||
<kbd><c-o></kbd>: 複製分支名稱到剪貼簿
|
|-----|--------|-------------|
|
||||||
<kbd><space></kbd>: 檢出
|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
||||||
<kbd>n</kbd>: 新分支
|
| `` <space> `` | 檢出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
<kbd>M</kbd>: 合併到當前檢出的分支
|
| `` n `` | 新分支 | |
|
||||||
<kbd>r</kbd>: 將已檢出的分支變基至此分支
|
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
<kbd>d</kbd>: 刪除分支
|
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
<kbd>u</kbd>: 將此分支設為當前分支之上游
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
| `` u `` | Set as upstream | 將此分支設為當前分支之上游 |
|
||||||
<kbd><enter></kbd>: 檢視提交
|
| `` s `` | Sort order | |
|
||||||
<kbd>/</kbd>: Filter the current view by text
|
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
</pre>
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
|
| `` <enter> `` | 檢視提交 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|||||||
@@ -1,74 +1,82 @@
|
|||||||
module github.com/jesseduffield/lazygit
|
module github.com/jesseduffield/lazygit
|
||||||
|
|
||||||
go 1.18
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/OpenPeeDeeP/xdg v1.0.0
|
github.com/adrg/xdg v0.4.0
|
||||||
github.com/atotto/clipboard v0.1.4
|
github.com/atotto/clipboard v0.1.4
|
||||||
github.com/aybabtme/humanlog v0.4.1
|
github.com/aybabtme/humanlog v0.4.1
|
||||||
github.com/cli/safeexec v1.0.0
|
|
||||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||||
github.com/creack/pty v1.1.11
|
github.com/creack/pty v1.1.11
|
||||||
github.com/fsmiamoto/git-todo-parser v0.0.5
|
github.com/gdamore/tcell/v2 v2.7.4
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/go-errors/errors v1.5.1
|
||||||
github.com/gdamore/tcell/v2 v2.6.0
|
|
||||||
github.com/go-errors/errors v1.4.2
|
|
||||||
github.com/gookit/color v1.4.2
|
github.com/gookit/color v1.4.2
|
||||||
|
github.com/iancoleman/orderedmap v0.3.0
|
||||||
github.com/imdario/mergo v0.3.11
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/integrii/flaggy v1.4.0
|
github.com/integrii/flaggy v1.4.0
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b
|
github.com/jesseduffield/gocui v0.3.1-0.20240628061234-aed9e133e65b
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
|
||||||
|
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3
|
||||||
github.com/kyokomi/emoji/v2 v2.2.8
|
github.com/kyokomi/emoji/v2 v2.2.8
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||||
github.com/mattn/go-runewidth v0.0.14
|
github.com/mattn/go-runewidth v0.0.15
|
||||||
github.com/mgutz/str v1.2.0
|
github.com/mgutz/str v1.2.0
|
||||||
github.com/pmezard/go-difflib v1.0.0
|
github.com/mitchellh/go-ps v1.0.0
|
||||||
github.com/sahilm/fuzzy v0.1.0
|
github.com/sahilm/fuzzy v0.1.0
|
||||||
github.com/samber/lo v1.31.0
|
github.com/samber/lo v1.31.0
|
||||||
github.com/sanity-io/litter v1.5.2
|
github.com/sanity-io/litter v1.5.2
|
||||||
github.com/sasha-s/go-deadlock v0.3.1
|
github.com/sasha-s/go-deadlock v0.3.1
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/spf13/afero v1.9.5
|
||||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2
|
||||||
|
github.com/stretchr/testify v1.8.1
|
||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
|
||||||
|
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8
|
||||||
|
golang.org/x/sync v0.7.0
|
||||||
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
|
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/emirpasic/gods v1.12.0 // indirect
|
github.com/emirpasic/gods v1.12.0 // indirect
|
||||||
github.com/fatih/color v1.9.0 // indirect
|
github.com/fatih/color v1.9.0 // indirect
|
||||||
github.com/gdamore/encoding v1.0.0 // indirect
|
github.com/gdamore/encoding v1.0.1 // indirect
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.0.0 // indirect
|
github.com/go-git/go-billy/v5 v5.0.0 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||||
github.com/gobwas/glob v0.2.3 // indirect
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/google/go-cmp v0.5.6 // indirect
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
|
github.com/invopop/jsonschema v0.10.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||||
github.com/onsi/gomega v1.7.1 // indirect
|
github.com/onsi/gomega v1.7.1 // indirect
|
||||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/sergi/go-diff v1.1.0 // indirect
|
github.com/sergi/go-diff v1.1.0 // indirect
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
golang.org/x/sys v0.21.0 // indirect
|
||||||
golang.org/x/term v0.10.0 // indirect
|
golang.org/x/term v0.21.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,45 @@
|
|||||||
github.com/OpenPeeDeeP/xdg v1.0.0 h1:UDLmNjCGFZZCaVMB74DqYEtXkHxnTxcr4FeJVF9uCn8=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/OpenPeeDeeP/xdg v1.0.0/go.mod h1:tMoSueLQlMf0TCldjrJLNIjAc5qAOIcHt5REi88/Ygo=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||||
|
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||||
|
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||||
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||||
|
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
@@ -11,10 +51,20 @@ github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn
|
|||||||
github.com/aybabtme/humanlog v0.4.1 h1:D8d9um55rrthJsP8IGSHBcti9lTb/XknmDAX6Zy8tek=
|
github.com/aybabtme/humanlog v0.4.1 h1:D8d9um55rrthJsP8IGSHBcti9lTb/XknmDAX6Zy8tek=
|
||||||
github.com/aybabtme/humanlog v0.4.1/go.mod h1:B0bnQX4FTSU3oftPMTTPvENCy8LqixLDvYJA9TUCAGo=
|
github.com/aybabtme/humanlog v0.4.1/go.mod h1:B0bnQX4FTSU3oftPMTTPvENCy8LqixLDvYJA9TUCAGo=
|
||||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||||
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
|
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
@@ -24,56 +74,122 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
github.com/fsmiamoto/git-todo-parser v0.0.5 h1:Bhzd/vz/6Qm3udfkd6NO9fWfD3TpwR9ucp3N75/J5I8=
|
|
||||||
github.com/fsmiamoto/git-todo-parser v0.0.5/go.mod h1:B+AgTbNE2BARvJqzXygThzqxLIaEWvwr2sxKYYb0Fas=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||||
github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg=
|
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||||
github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y=
|
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
||||||
|
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||||
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
|
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
|
||||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
|
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
|
||||||
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
||||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
|
||||||
|
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM=
|
github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM=
|
||||||
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
|
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
|
||||||
|
github.com/invopop/jsonschema v0.10.0 h1:c1ktzNLBun3LyQQhyty5WE3lulbOdIIyOVlkmDLehcE=
|
||||||
|
github.com/invopop/jsonschema v0.10.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8TIcC6Y4RI+1ZbJDOHfGJ570tPeYVCqo7/tws=
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8TIcC6Y4RI+1ZbJDOHfGJ570tPeYVCqo7/tws=
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b h1:8FmmdaYHes1m3oNyNdS+VIgkgkFpNZAWuwTnvp0tG14=
|
github.com/jesseduffield/gocui v0.3.1-0.20240628061234-aed9e133e65b h1:oxCq0DvR2GMGf4UaoaASb0nQK/fJMQW3c3PNCLWCjS8=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230710004407-9bbfd873713b/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
|
github.com/jesseduffield/gocui v0.3.1-0.20240628061234-aed9e133e65b/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||||
@@ -81,13 +197,20 @@ github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:q
|
|||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
|
||||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
|
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3 h1:s995u+gNQADMaixtNOs+jilRC/Q78q0UXSI7+4T0cDE=
|
||||||
|
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3/go.mod h1:MCbEh21gjOzxc31udr3u4QM9DAdf8TFJCZz3u5hYIxA=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -99,9 +222,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
|||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE=
|
github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE=
|
||||||
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
|
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||||
@@ -111,13 +235,14 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
|
||||||
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
|
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||||
|
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
@@ -127,16 +252,19 @@ github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
|||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
|
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
|
||||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
|
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
|
github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
|
||||||
@@ -149,88 +277,373 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
|||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||||
|
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
|
||||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||||
|
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2 h1:RTNWemd/9z9A5L/AggEP3OdhRz5dXETB/wdAlYF0SuM=
|
||||||
|
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2/go.mod h1:HFt9hGqMzgQ+gVxMKcvTvGaFz4Y0yYycqqAp2V3wcJY=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||||
|
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||||
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
|
||||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||||
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
|
||||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||||
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
|
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
|
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||||
|
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||||
|
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||||
|
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 h1:KzcWKJ0nMAmGoBhYVMnkWc1rXjB42lKy5aIys4TdLOA=
|
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 h1:KzcWKJ0nMAmGoBhYVMnkWc1rXjB42lKy5aIys4TdLOA=
|
||||||
@@ -246,3 +659,13 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
|||||||
+30
-16
@@ -11,10 +11,9 @@ import (
|
|||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
appTypes "github.com/jesseduffield/lazygit/pkg/app/types"
|
appTypes "github.com/jesseduffield/lazygit/pkg/app/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
@@ -23,6 +22,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/env"
|
"github.com/jesseduffield/lazygit/pkg/env"
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui"
|
"github.com/jesseduffield/lazygit/pkg/gui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/logs"
|
"github.com/jesseduffield/lazygit/pkg/logs"
|
||||||
"github.com/jesseduffield/lazygit/pkg/updates"
|
"github.com/jesseduffield/lazygit/pkg/updates"
|
||||||
)
|
)
|
||||||
@@ -42,7 +42,7 @@ func Run(
|
|||||||
common *common.Common,
|
common *common.Common,
|
||||||
startArgs appTypes.StartArgs,
|
startArgs appTypes.StartArgs,
|
||||||
) {
|
) {
|
||||||
app, err := NewApp(config, common)
|
app, err := NewApp(config, startArgs.IntegrationTest, common)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = app.Run(startArgs)
|
err = app.Run(startArgs)
|
||||||
@@ -62,6 +62,7 @@ func Run(
|
|||||||
|
|
||||||
func NewCommon(config config.AppConfigurer) (*common.Common, error) {
|
func NewCommon(config config.AppConfigurer) (*common.Common, error) {
|
||||||
userConfig := config.GetUserConfig()
|
userConfig := config.GetUserConfig()
|
||||||
|
appState := config.GetAppState()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
log := newLogger(config)
|
log := newLogger(config)
|
||||||
@@ -74,7 +75,9 @@ func NewCommon(config config.AppConfigurer) (*common.Common, error) {
|
|||||||
Log: log,
|
Log: log,
|
||||||
Tr: tr,
|
Tr: tr,
|
||||||
UserConfig: userConfig,
|
UserConfig: userConfig,
|
||||||
|
AppState: appState,
|
||||||
Debug: config.GetDebug(),
|
Debug: config.GetDebug(),
|
||||||
|
Fs: afero.NewOsFs(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +94,7 @@ func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewApp bootstrap a new application
|
// NewApp bootstrap a new application
|
||||||
func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
|
func NewApp(config config.AppConfigurer, test integrationTypes.IntegrationTest, common *common.Common) (*App, error) {
|
||||||
app := &App{
|
app := &App{
|
||||||
closers: []io.Closer{},
|
closers: []io.Closer{},
|
||||||
Config: config,
|
Config: config,
|
||||||
@@ -115,7 +118,14 @@ func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
|
|||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
|
|
||||||
showRecentRepos, err := app.setupRepo()
|
// If we're not in a repo, repoPaths will be nil. The error is moot for us
|
||||||
|
// at this stage, since we'll try to init a new repo in setupRepo(), below
|
||||||
|
repoPaths, err := git_commands.GetRepoPaths(app.OSCommand.Cmd, gitVersion)
|
||||||
|
if err != nil {
|
||||||
|
return app, err
|
||||||
|
}
|
||||||
|
|
||||||
|
showRecentRepos, err := app.setupRepo(repoPaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
@@ -125,7 +135,7 @@ func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
|
|||||||
showRecentRepos = true
|
showRecentRepos = true
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Gui, err = gui.NewGui(common, config, gitVersion, updater, showRecentRepos, dirName)
|
app.Gui, err = gui.NewGui(common, config, gitVersion, updater, showRecentRepos, dirName, test)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
@@ -164,14 +174,16 @@ func openRecentRepo(app *App) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *App) setupRepo() (bool, error) {
|
func (app *App) setupRepo(
|
||||||
|
repoPaths *git_commands.RepoPaths,
|
||||||
|
) (bool, error) {
|
||||||
if env.GetGitDirEnv() != "" {
|
if env.GetGitDirEnv() != "" {
|
||||||
// we've been given the git dir directly. We'll verify this dir when initializing our Git object
|
// we've been given the git dir directly. Skip setup
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are not in a git repo, we ask if we want to `git init`
|
// if we are not in a git repo, we ask if we want to `git init`
|
||||||
if err := commands.VerifyInGitRepo(app.OSCommand); err != nil {
|
if repoPaths == nil {
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -217,6 +229,7 @@ func (app *App) setupRepo() (bool, error) {
|
|||||||
if err := app.OSCommand.Cmd.New(args).Run(); err != nil {
|
if err := app.OSCommand.Cmd.New(args).Run(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,10 +247,7 @@ func (app *App) setupRepo() (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run this afterward so that the previous repo creation steps can run without this interfering
|
// Run this afterward so that the previous repo creation steps can run without this interfering
|
||||||
if isBare, err := git_commands.IsBareRepo(app.OSCommand); isBare {
|
if repoPaths.IsBareRepo() {
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Print(app.Tr.BareRepo)
|
fmt.Print(app.Tr.BareRepo)
|
||||||
|
|
||||||
@@ -265,7 +275,11 @@ func (app *App) Run(startArgs appTypes.StartArgs) error {
|
|||||||
|
|
||||||
// Close closes any resources
|
// Close closes any resources
|
||||||
func (app *App) Close() error {
|
func (app *App) Close() error {
|
||||||
return slices.TryForEach(app.closers, func(closer io.Closer) error {
|
for _, closer := range app.closers {
|
||||||
return closer.Close()
|
if err := closer.Close(); err != nil {
|
||||||
})
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+108
-44
@@ -5,14 +5,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sometimes lazygit will be invoked in daemon mode from a parent lazygit process.
|
// Sometimes lazygit will be invoked in daemon mode from a parent lazygit process.
|
||||||
@@ -33,12 +33,14 @@ const (
|
|||||||
DaemonKindUnknown DaemonKind = iota
|
DaemonKindUnknown DaemonKind = iota
|
||||||
|
|
||||||
DaemonKindExitImmediately
|
DaemonKindExitImmediately
|
||||||
|
DaemonKindRemoveUpdateRefsForCopiedBranch
|
||||||
DaemonKindCherryPick
|
DaemonKindCherryPick
|
||||||
DaemonKindMoveTodoUp
|
DaemonKindMoveTodosUp
|
||||||
DaemonKindMoveTodoDown
|
DaemonKindMoveTodosDown
|
||||||
DaemonKindInsertBreak
|
DaemonKindInsertBreak
|
||||||
DaemonKindChangeTodoActions
|
DaemonKindChangeTodoActions
|
||||||
DaemonKindMoveFixupCommitDown
|
DaemonKindMoveFixupCommitDown
|
||||||
|
DaemonKindWriteRebaseTodo
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -52,13 +54,15 @@ func getInstruction() Instruction {
|
|||||||
jsonData := os.Getenv(DaemonInstructionEnvKey)
|
jsonData := os.Getenv(DaemonInstructionEnvKey)
|
||||||
|
|
||||||
mapping := map[DaemonKind]func(string) Instruction{
|
mapping := map[DaemonKind]func(string) Instruction{
|
||||||
DaemonKindExitImmediately: deserializeInstruction[*ExitImmediatelyInstruction],
|
DaemonKindExitImmediately: deserializeInstruction[*ExitImmediatelyInstruction],
|
||||||
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
|
DaemonKindRemoveUpdateRefsForCopiedBranch: deserializeInstruction[*RemoveUpdateRefsForCopiedBranchInstruction],
|
||||||
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
|
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
|
||||||
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
|
||||||
DaemonKindMoveTodoUp: deserializeInstruction[*MoveTodoUpInstruction],
|
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
||||||
DaemonKindMoveTodoDown: deserializeInstruction[*MoveTodoDownInstruction],
|
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
||||||
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
||||||
|
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
||||||
|
DaemonKindWriteRebaseTodo: deserializeInstruction[*WriteRebaseTodoInstruction],
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping[getDaemonKind()](jsonData)
|
return mapping[getDaemonKind()](jsonData)
|
||||||
@@ -92,7 +96,7 @@ func getDaemonKind() DaemonKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCommentChar() byte {
|
func getCommentChar() byte {
|
||||||
cmd := secureexec.Command("git", "config", "--get", "--null", "core.commentChar")
|
cmd := exec.Command("git", "config", "--get", "--null", "core.commentChar")
|
||||||
if output, err := cmd.Output(); err == nil && len(output) == 2 {
|
if output, err := cmd.Output(); err == nil && len(output) == 2 {
|
||||||
return output[0]
|
return output[0]
|
||||||
}
|
}
|
||||||
@@ -155,6 +159,26 @@ func NewExitImmediatelyInstruction() Instruction {
|
|||||||
return &ExitImmediatelyInstruction{}
|
return &ExitImmediatelyInstruction{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RemoveUpdateRefsForCopiedBranchInstruction struct{}
|
||||||
|
|
||||||
|
func (self *RemoveUpdateRefsForCopiedBranchInstruction) Kind() DaemonKind {
|
||||||
|
return DaemonKindRemoveUpdateRefsForCopiedBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RemoveUpdateRefsForCopiedBranchInstruction) SerializedInstructions() string {
|
||||||
|
return serializeInstruction(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RemoveUpdateRefsForCopiedBranchInstruction) run(common *common.Common) error {
|
||||||
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRemoveUpdateRefsForCopiedBranchInstruction() Instruction {
|
||||||
|
return &RemoveUpdateRefsForCopiedBranchInstruction{}
|
||||||
|
}
|
||||||
|
|
||||||
type CherryPickCommitsInstruction struct {
|
type CherryPickCommitsInstruction struct {
|
||||||
Todo string
|
Todo string
|
||||||
}
|
}
|
||||||
@@ -208,28 +232,30 @@ func (self *ChangeTodoActionsInstruction) SerializedInstructions() string {
|
|||||||
|
|
||||||
func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
for _, c := range self.Changes {
|
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
|
||||||
if err := utils.EditRebaseTodo(path, c.Sha, todo.Pick, c.NewAction, getCommentChar()); err != nil {
|
return utils.TodoChange{
|
||||||
return err
|
Hash: c.Hash,
|
||||||
|
OldAction: todo.Pick,
|
||||||
|
NewAction: c.NewAction,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
return nil
|
return utils.EditRebaseTodo(path, changes, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes the sha of some commit, and the sha of a fixup commit that was created
|
// Takes the hash of some commit, and the hash of a fixup commit that was created
|
||||||
// at the end of the branch, then moves the fixup commit down to right after the
|
// at the end of the branch, then moves the fixup commit down to right after the
|
||||||
// original commit, changing its type to "fixup"
|
// original commit, changing its type to "fixup"
|
||||||
type MoveFixupCommitDownInstruction struct {
|
type MoveFixupCommitDownInstruction struct {
|
||||||
OriginalSha string
|
OriginalHash string
|
||||||
FixupSha string
|
FixupHash string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveFixupCommitDownInstruction(originalSha string, fixupSha string) Instruction {
|
func NewMoveFixupCommitDownInstruction(originalHash string, fixupHash string) Instruction {
|
||||||
return &MoveFixupCommitDownInstruction{
|
return &MoveFixupCommitDownInstruction{
|
||||||
OriginalSha: originalSha,
|
OriginalHash: originalHash,
|
||||||
FixupSha: fixupSha,
|
FixupHash: fixupHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,55 +269,69 @@ func (self *MoveFixupCommitDownInstruction) SerializedInstructions() string {
|
|||||||
|
|
||||||
func (self *MoveFixupCommitDownInstruction) run(common *common.Common) error {
|
func (self *MoveFixupCommitDownInstruction) run(common *common.Common) error {
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveFixupCommitDown(path, self.OriginalSha, self.FixupSha, getCommentChar())
|
return utils.MoveFixupCommitDown(path, self.OriginalHash, self.FixupHash, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodoUpInstruction struct {
|
type MoveTodosUpInstruction struct {
|
||||||
Sha string
|
Hashes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodoUpInstruction(sha string) Instruction {
|
func NewMoveTodosUpInstruction(hashes []string) Instruction {
|
||||||
return &MoveTodoUpInstruction{
|
return &MoveTodosUpInstruction{
|
||||||
Sha: sha,
|
Hashes: hashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) Kind() DaemonKind {
|
func (self *MoveTodosUpInstruction) Kind() DaemonKind {
|
||||||
return DaemonKindMoveTodoUp
|
return DaemonKindMoveTodosUp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) SerializedInstructions() string {
|
func (self *MoveTodosUpInstruction) SerializedInstructions() string {
|
||||||
return serializeInstruction(self)
|
return serializeInstruction(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoUpInstruction) run(common *common.Common) error {
|
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
|
||||||
|
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Hash: hash,
|
||||||
|
Action: todo.Pick,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodoUp(path, self.Sha, todo.Pick, getCommentChar())
|
return utils.MoveTodosUp(path, todosToMove, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodoDownInstruction struct {
|
type MoveTodosDownInstruction struct {
|
||||||
Sha string
|
Hashes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodoDownInstruction(sha string) Instruction {
|
func NewMoveTodosDownInstruction(hashes []string) Instruction {
|
||||||
return &MoveTodoDownInstruction{
|
return &MoveTodosDownInstruction{
|
||||||
Sha: sha,
|
Hashes: hashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) Kind() DaemonKind {
|
func (self *MoveTodosDownInstruction) Kind() DaemonKind {
|
||||||
return DaemonKindMoveTodoDown
|
return DaemonKindMoveTodosDown
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) SerializedInstructions() string {
|
func (self *MoveTodosDownInstruction) SerializedInstructions() string {
|
||||||
return serializeInstruction(self)
|
return serializeInstruction(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodoDownInstruction) run(common *common.Common) error {
|
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
|
||||||
|
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||||
|
return utils.Todo{
|
||||||
|
Hash: hash,
|
||||||
|
Action: todo.Pick,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodoDown(path, self.Sha, todo.Pick, getCommentChar())
|
return utils.MoveTodosDown(path, todosToMove, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,3 +354,27 @@ func (self *InsertBreakInstruction) run(common *common.Common) error {
|
|||||||
return utils.PrependStrToTodoFile(path, []byte("break\n"))
|
return utils.PrependStrToTodoFile(path, []byte("break\n"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WriteRebaseTodoInstruction struct {
|
||||||
|
TodosFileContent []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWriteRebaseTodoInstruction(todosFileContent []byte) Instruction {
|
||||||
|
return &WriteRebaseTodoInstruction{
|
||||||
|
TodosFileContent: todosFileContent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) Kind() DaemonKind {
|
||||||
|
return DaemonKindWriteRebaseTodo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) SerializedInstructions() string {
|
||||||
|
return serializeInstruction(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WriteRebaseTodoInstruction) run(common *common.Common) error {
|
||||||
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
|
return os.WriteFile(path, self.TodosFileContent, 0o644)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/env"
|
"github.com/jesseduffield/lazygit/pkg/env"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TodoLine struct {
|
type TodoLine struct {
|
||||||
@@ -21,20 +22,20 @@ func (self *TodoLine) ToString() string {
|
|||||||
if self.Action == "break" {
|
if self.Action == "break" {
|
||||||
return self.Action + "\n"
|
return self.Action + "\n"
|
||||||
} else {
|
} else {
|
||||||
return self.Action + " " + self.Commit.Sha + " " + self.Commit.Name + "\n"
|
return self.Action + " " + self.Commit.Hash + " " + self.Commit.Name + "\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TodoLinesToString(todoLines []TodoLine) string {
|
func TodoLinesToString(todoLines []TodoLine) string {
|
||||||
lines := slices.Map(todoLines, func(todoLine TodoLine) string {
|
lines := lo.Map(todoLines, func(todoLine TodoLine, _ int) string {
|
||||||
return todoLine.ToString()
|
return todoLine.ToString()
|
||||||
})
|
})
|
||||||
|
|
||||||
return strings.Join(slices.Reverse(lines), "")
|
return strings.Join(lo.Reverse(lines), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChangeTodoAction struct {
|
type ChangeTodoAction struct {
|
||||||
Sha string
|
Hash string
|
||||||
NewAction todo.TodoCommand
|
NewAction todo.TodoCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +45,10 @@ func handleInteractiveRebase(common *common.Common, f func(path string) error) e
|
|||||||
path := os.Args[1]
|
path := os.Args[1]
|
||||||
|
|
||||||
if strings.HasSuffix(path, "git-rebase-todo") {
|
if strings.HasSuffix(path, "git-rebase-todo") {
|
||||||
|
err := utils.RemoveUpdateRefsForCopiedBranch(path, getCommentChar())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return f(path)
|
return f(path)
|
||||||
} else if strings.HasSuffix(path, filepath.Join(gitDir(), "COMMIT_EDITMSG")) { // TODO: test
|
} else if strings.HasSuffix(path, filepath.Join(gitDir(), "COMMIT_EDITMSG")) { // TODO: test
|
||||||
// if we are rebasing and squashing, we'll see a COMMIT_EDITMSG
|
// if we are rebasing and squashing, we'll see a COMMIT_EDITMSG
|
||||||
|
|||||||
+30
-16
@@ -4,7 +4,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
@@ -17,7 +20,6 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/env"
|
"github.com/jesseduffield/lazygit/pkg/env"
|
||||||
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/logs/tail"
|
"github.com/jesseduffield/lazygit/pkg/logs/tail"
|
||||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -30,6 +32,7 @@ type cliArgs struct {
|
|||||||
PrintVersionInfo bool
|
PrintVersionInfo bool
|
||||||
Debug bool
|
Debug bool
|
||||||
TailLogs bool
|
TailLogs bool
|
||||||
|
Profile bool
|
||||||
PrintDefaultConfig bool
|
PrintDefaultConfig bool
|
||||||
PrintConfigDir bool
|
PrintConfigDir bool
|
||||||
UseConfigDir string
|
UseConfigDir string
|
||||||
@@ -63,8 +66,17 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
log.Fatal(absRepoPath + " is not a valid git repository.")
|
log.Fatal(absRepoPath + " is not a valid git repository.")
|
||||||
}
|
}
|
||||||
|
|
||||||
cliArgs.WorkTree = absRepoPath
|
|
||||||
cliArgs.GitDir = filepath.Join(absRepoPath, ".git")
|
cliArgs.GitDir = filepath.Join(absRepoPath, ".git")
|
||||||
|
err = os.Chdir(absRepoPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to change directory to %s: %v", absRepoPath, err)
|
||||||
|
}
|
||||||
|
} else if cliArgs.WorkTree != "" {
|
||||||
|
env.SetWorkTreeEnv(cliArgs.WorkTree)
|
||||||
|
|
||||||
|
if err := os.Chdir(cliArgs.WorkTree); err != nil {
|
||||||
|
log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliArgs.CustomConfigFile != "" {
|
if cliArgs.CustomConfigFile != "" {
|
||||||
@@ -75,10 +87,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir)
|
os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliArgs.WorkTree != "" {
|
|
||||||
env.SetGitWorkTreeEnv(cliArgs.WorkTree)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cliArgs.GitDir != "" {
|
if cliArgs.GitDir != "" {
|
||||||
env.SetGitDirEnv(cliArgs.GitDir)
|
env.SetGitDirEnv(cliArgs.GitDir)
|
||||||
}
|
}
|
||||||
@@ -115,12 +123,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliArgs.WorkTree != "" {
|
|
||||||
if err := os.Chdir(cliArgs.WorkTree); err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir, err := os.MkdirTemp("", "lazygit-*")
|
tempDir, err := os.MkdirTemp("", "lazygit-*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
@@ -146,6 +148,14 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cliArgs.Profile {
|
||||||
|
go func() {
|
||||||
|
if err := http.ListenAndServe("localhost:6060", nil); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
parsedGitArg := parseGitArg(cliArgs.GitArg)
|
parsedGitArg := parseGitArg(cliArgs.GitArg)
|
||||||
|
|
||||||
Run(appConfig, common, appTypes.NewStartArgs(cliArgs.FilterPath, parsedGitArg, integrationTest))
|
Run(appConfig, common, appTypes.NewStartArgs(cliArgs.FilterPath, parsedGitArg, integrationTest))
|
||||||
@@ -172,6 +182,9 @@ func parseCliArgsAndEnvVars() *cliArgs {
|
|||||||
tailLogs := false
|
tailLogs := false
|
||||||
flaggy.Bool(&tailLogs, "l", "logs", "Tail lazygit logs (intended to be used when `lazygit --debug` is called in a separate terminal tab)")
|
flaggy.Bool(&tailLogs, "l", "logs", "Tail lazygit logs (intended to be used when `lazygit --debug` is called in a separate terminal tab)")
|
||||||
|
|
||||||
|
profile := false
|
||||||
|
flaggy.Bool(&profile, "", "profile", "Start the profiler and serve it on http port 6060. See CONTRIBUTING.md for more info.")
|
||||||
|
|
||||||
printDefaultConfig := false
|
printDefaultConfig := false
|
||||||
flaggy.Bool(&printDefaultConfig, "c", "config", "Print the default config")
|
flaggy.Bool(&printDefaultConfig, "c", "config", "Print the default config")
|
||||||
|
|
||||||
@@ -181,10 +194,10 @@ func parseCliArgsAndEnvVars() *cliArgs {
|
|||||||
useConfigDir := ""
|
useConfigDir := ""
|
||||||
flaggy.String(&useConfigDir, "ucd", "use-config-dir", "override default config directory with provided directory")
|
flaggy.String(&useConfigDir, "ucd", "use-config-dir", "override default config directory with provided directory")
|
||||||
|
|
||||||
workTree := ""
|
workTree := os.Getenv("GIT_WORK_TREE")
|
||||||
flaggy.String(&workTree, "w", "work-tree", "equivalent of the --work-tree git argument")
|
flaggy.String(&workTree, "w", "work-tree", "equivalent of the --work-tree git argument")
|
||||||
|
|
||||||
gitDir := ""
|
gitDir := os.Getenv("GIT_DIR")
|
||||||
flaggy.String(&gitDir, "g", "git-dir", "equivalent of the --git-dir git argument")
|
flaggy.String(&gitDir, "g", "git-dir", "equivalent of the --git-dir git argument")
|
||||||
|
|
||||||
customConfigFile := ""
|
customConfigFile := ""
|
||||||
@@ -203,6 +216,7 @@ func parseCliArgsAndEnvVars() *cliArgs {
|
|||||||
PrintVersionInfo: printVersionInfo,
|
PrintVersionInfo: printVersionInfo,
|
||||||
Debug: debug,
|
Debug: debug,
|
||||||
TailLogs: tailLogs,
|
TailLogs: tailLogs,
|
||||||
|
Profile: profile,
|
||||||
PrintDefaultConfig: printDefaultConfig,
|
PrintDefaultConfig: printDefaultConfig,
|
||||||
PrintConfigDir: printConfigDir,
|
PrintConfigDir: printConfigDir,
|
||||||
UseConfigDir: useConfigDir,
|
UseConfigDir: useConfigDir,
|
||||||
@@ -264,7 +278,7 @@ func mergeBuildInfo(buildInfo *BuildInfo) {
|
|||||||
buildInfo.Commit = revision.Value
|
buildInfo.Commit = revision.Value
|
||||||
// if lazygit was built from source we'll show the version as the
|
// if lazygit was built from source we'll show the version as the
|
||||||
// abbreviated commit hash
|
// abbreviated commit hash
|
||||||
buildInfo.Version = utils.ShortSha(revision.Value)
|
buildInfo.Version = utils.ShortHash(revision.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if version hasn't been set we assume that neither has the date
|
// if version hasn't been set we assume that neither has the date
|
||||||
@@ -277,7 +291,7 @@ func mergeBuildInfo(buildInfo *BuildInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getGitVersionInfo() string {
|
func getGitVersionInfo() string {
|
||||||
cmd := secureexec.Command("git", "--version")
|
cmd := exec.Command("git", "--version")
|
||||||
stdout, _ := cmd.Output()
|
stdout, _ := cmd.Output()
|
||||||
gitVersion := strings.Trim(strings.TrimPrefix(string(stdout), "git version "), " \r\n")
|
gitVersion := strings.Trim(strings.TrimPrefix(string(stdout), "git version "), " \r\n")
|
||||||
return gitVersion
|
return gitVersion
|
||||||
|
|||||||
+7
-3
@@ -3,8 +3,8 @@ package app
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type errorMapping struct {
|
type errorMapping struct {
|
||||||
@@ -18,7 +18,7 @@ func knownError(tr *i18n.TranslationSet, err error) (string, bool) {
|
|||||||
|
|
||||||
knownErrorMessages := []string{tr.MinGitVersionError}
|
knownErrorMessages := []string{tr.MinGitVersionError}
|
||||||
|
|
||||||
if slices.Contains(knownErrorMessages, errorMessage) {
|
if lo.Contains(knownErrorMessages, errorMessage) {
|
||||||
return errorMessage, true
|
return errorMessage, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,9 +27,13 @@ func knownError(tr *i18n.TranslationSet, err error) (string, bool) {
|
|||||||
originalError: "fatal: not a git repository",
|
originalError: "fatal: not a git repository",
|
||||||
newError: tr.NotARepository,
|
newError: tr.NotARepository,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
originalError: "getwd: no such file or directory",
|
||||||
|
newError: tr.WorkingDirectoryDoesNotExist,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if mapping, ok := slices.Find(mappings, func(mapping errorMapping) bool {
|
if mapping, ok := lo.Find(mappings, func(mapping errorMapping) bool {
|
||||||
return strings.Contains(errorMessage, mapping.originalError)
|
return strings.Contains(errorMessage, mapping.originalError)
|
||||||
}); ok {
|
}); ok {
|
||||||
return mapping.newError, true
|
return mapping.newError, true
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package cheatsheet
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/pmezard/go-difflib/difflib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Check() {
|
|
||||||
dir := GetKeybindingsDir()
|
|
||||||
tmpDir := filepath.Join(os.TempDir(), "lazygit_cheatsheet")
|
|
||||||
err := os.RemoveAll(tmpDir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
|
|
||||||
}
|
|
||||||
err = os.Mkdir(tmpDir, 0o700)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
generateAtDir(tmpDir)
|
|
||||||
defer os.RemoveAll(tmpDir)
|
|
||||||
|
|
||||||
actualContent := obtainContent(dir)
|
|
||||||
expectedContent := obtainContent(tmpDir)
|
|
||||||
|
|
||||||
if expectedContent == "" {
|
|
||||||
log.Fatal("empty expected content")
|
|
||||||
}
|
|
||||||
|
|
||||||
if actualContent != expectedContent {
|
|
||||||
err := difflib.WriteUnifiedDiff(os.Stdout, difflib.UnifiedDiff{
|
|
||||||
A: difflib.SplitLines(expectedContent),
|
|
||||||
B: difflib.SplitLines(actualContent),
|
|
||||||
FromFile: "Expected",
|
|
||||||
FromDate: "",
|
|
||||||
ToFile: "Actual",
|
|
||||||
ToDate: "",
|
|
||||||
Context: 1,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Printf("\nCheatsheets are out of date. Please run `%s` at the project root and commit the changes. If you run the script and no keybindings files are updated as a result, try rebasing onto master and trying again.\n", CommandToRun())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("\nCheatsheets are up to date")
|
|
||||||
}
|
|
||||||
|
|
||||||
func obtainContent(dir string) string {
|
|
||||||
re := regexp.MustCompile(`Keybindings_\w+\.md$`)
|
|
||||||
|
|
||||||
content := ""
|
|
||||||
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
|
|
||||||
if re.MatchString(path) {
|
|
||||||
bytes, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
|
|
||||||
}
|
|
||||||
content += fmt.Sprintf("\n%s\n\n", filepath.Base(path))
|
|
||||||
content += string(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
+26
-25
@@ -1,10 +1,12 @@
|
|||||||
// This "script" generates a file called Keybindings_{{.LANG}}.md
|
//go:generate go run generator.go
|
||||||
// in current working directory.
|
|
||||||
|
// This "script" generates files called Keybindings_{{.LANG}}.md
|
||||||
|
// in the docs/keybindings directory.
|
||||||
//
|
//
|
||||||
// The content of this generated file is a keybindings cheatsheet.
|
// The content of these generated files is a keybindings cheatsheet.
|
||||||
//
|
//
|
||||||
// To generate cheatsheet in english run:
|
// To generate the cheatsheets, run:
|
||||||
// go run scripts/generate_cheatsheet.go
|
// go generate pkg/cheatsheet/generate.go
|
||||||
|
|
||||||
package cheatsheet
|
package cheatsheet
|
||||||
|
|
||||||
@@ -12,10 +14,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/maps"
|
"github.com/jesseduffield/generics/maps"
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazycore/pkg/utils"
|
"github.com/jesseduffield/lazycore/pkg/utils"
|
||||||
"github.com/jesseduffield/lazygit/pkg/app"
|
"github.com/jesseduffield/lazygit/pkg/app"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bindingSection struct {
|
type bindingSection struct {
|
||||||
@@ -42,7 +43,7 @@ type headerWithBindings struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CommandToRun() string {
|
func CommandToRun() string {
|
||||||
return "go run scripts/cheatsheet/main.go generate"
|
return "go generate ./..."
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetKeybindingsDir() string {
|
func GetKeybindingsDir() string {
|
||||||
@@ -50,7 +51,10 @@ func GetKeybindingsDir() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateAtDir(cheatsheetDir string) {
|
func generateAtDir(cheatsheetDir string) {
|
||||||
translationSetsByLang := i18n.GetTranslationSets()
|
translationSetsByLang, err := i18n.GetTranslationSets()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
mConfig := config.NewDummyAppConfig()
|
mConfig := config.NewDummyAppConfig()
|
||||||
|
|
||||||
for lang := range translationSetsByLang {
|
for lang := range translationSetsByLang {
|
||||||
@@ -59,7 +63,7 @@ func generateAtDir(cheatsheetDir string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
mApp, _ := app.NewApp(mConfig, common)
|
mApp, _ := app.NewApp(mConfig, nil, common)
|
||||||
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
|
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -101,7 +105,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
|
|||||||
"reflogCommits": tr.ReflogCommitsTitle,
|
"reflogCommits": tr.ReflogCommitsTitle,
|
||||||
"tags": tr.TagsTitle,
|
"tags": tr.TagsTitle,
|
||||||
"commitFiles": tr.CommitFilesTitle,
|
"commitFiles": tr.CommitFilesTitle,
|
||||||
"commitMessage": tr.CommitMessageTitle,
|
"commitMessage": tr.CommitSummaryTitle,
|
||||||
"commitDescription": tr.CommitDescriptionTitle,
|
"commitDescription": tr.CommitDescriptionTitle,
|
||||||
"commits": tr.CommitsTitle,
|
"commits": tr.CommitsTitle,
|
||||||
"confirmation": tr.ConfirmationTitle,
|
"confirmation": tr.ConfirmationTitle,
|
||||||
@@ -116,6 +120,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
|
|||||||
"stash": tr.StashTitle,
|
"stash": tr.StashTitle,
|
||||||
"suggestions": tr.SuggestionsCheatsheetTitle,
|
"suggestions": tr.SuggestionsCheatsheetTitle,
|
||||||
"extras": tr.ExtrasTitle,
|
"extras": tr.ExtrasTitle,
|
||||||
|
"worktrees": tr.WorktreesTitle,
|
||||||
}
|
}
|
||||||
|
|
||||||
title, ok := contextTitleMap[str]
|
title, ok := contextTitleMap[str]
|
||||||
@@ -128,7 +133,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
|
|||||||
|
|
||||||
func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*bindingSection {
|
func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*bindingSection {
|
||||||
excludedViews := []string{"stagingSecondary", "patchBuildingSecondary"}
|
excludedViews := []string{"stagingSecondary", "patchBuildingSecondary"}
|
||||||
bindingsToDisplay := slices.Filter(bindings, func(binding *types.Binding) bool {
|
bindingsToDisplay := lo.Filter(bindings, func(binding *types.Binding, _ int) bool {
|
||||||
if lo.Contains(excludedViews, binding.ViewName) {
|
if lo.Contains(excludedViews, binding.ViewName) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -161,7 +166,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
|
|||||||
return a.header.title < b.header.title
|
return a.header.title < b.header.title
|
||||||
})
|
})
|
||||||
|
|
||||||
return slices.Map(bindingGroups, func(hb headerWithBindings) *bindingSection {
|
return lo.Map(bindingGroups, func(hb headerWithBindings, _ int) *bindingSection {
|
||||||
return &bindingSection{
|
return &bindingSection{
|
||||||
title: hb.header.title,
|
title: hb.header.title,
|
||||||
bindings: hb.bindings,
|
bindings: hb.bindings,
|
||||||
@@ -188,11 +193,11 @@ func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection)
|
|||||||
|
|
||||||
for _, section := range bindingSections {
|
for _, section := range bindingSections {
|
||||||
content += formatTitle(section.title)
|
content += formatTitle(section.title)
|
||||||
content += "<pre>\n"
|
content += "| Key | Action | Info |\n"
|
||||||
|
content += "|-----|--------|-------------|\n"
|
||||||
for _, binding := range section.bindings {
|
for _, binding := range section.bindings {
|
||||||
content += formatBinding(binding)
|
content += formatBinding(binding)
|
||||||
}
|
}
|
||||||
content += "</pre>\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return content
|
return content
|
||||||
@@ -203,19 +208,15 @@ func formatTitle(title string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func formatBinding(binding *types.Binding) string {
|
func formatBinding(binding *types.Binding) string {
|
||||||
result := fmt.Sprintf(" <kbd>%s</kbd>: %s", escapeAngleBrackets(keybindings.LabelFromKey(binding.Key)), binding.Description)
|
action := keybindings.LabelFromKey(binding.Key)
|
||||||
|
description := binding.Description
|
||||||
if binding.Alternative != "" {
|
if binding.Alternative != "" {
|
||||||
result += fmt.Sprintf(" (%s)", binding.Alternative)
|
action += fmt.Sprintf(" (%s)", binding.Alternative)
|
||||||
}
|
}
|
||||||
result += "\n"
|
|
||||||
|
|
||||||
return result
|
// Use backticks for keyboard keys. Two backticks are needed with an inner space
|
||||||
}
|
// to escape a key that is itself a backtick.
|
||||||
|
return fmt.Sprintf("| `` %s `` | %s | %s |\n", action, description, binding.Tooltip)
|
||||||
func escapeAngleBrackets(str string) string {
|
|
||||||
result := strings.ReplaceAll(str, ">", ">")
|
|
||||||
result = strings.ReplaceAll(result, "<", "<")
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func italicize(str string) string {
|
func italicize(str string) string {
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ func TestGetBindingSections(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.testName, func(t *testing.T) {
|
t.Run(test.testName, func(t *testing.T) {
|
||||||
actual := getBindingSections(test.bindings, &tr)
|
actual := getBindingSections(test.bindings, tr)
|
||||||
assert.EqualValues(t, test.expected, actual)
|
assert.EqualValues(t, test.expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/cheatsheet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Generating cheatsheets in %s...\n", cheatsheet.GetKeybindingsDir())
|
||||||
|
cheatsheet.Generate()
|
||||||
|
}
|
||||||
+33
-130
@@ -2,11 +2,9 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/sasha-s/go-deadlock"
|
|
||||||
|
|
||||||
gogit "github.com/jesseduffield/go-git/v5"
|
gogit "github.com/jesseduffield/go-git/v5"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||||
@@ -14,12 +12,12 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/env"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitCommand is our main git interface
|
// GitCommand is our main git interface
|
||||||
type GitCommand struct {
|
type GitCommand struct {
|
||||||
|
Blame *git_commands.BlameCommands
|
||||||
Branch *git_commands.BranchCommands
|
Branch *git_commands.BranchCommands
|
||||||
Commit *git_commands.CommitCommands
|
Commit *git_commands.CommitCommands
|
||||||
Config *git_commands.ConfigCommands
|
Config *git_commands.ConfigCommands
|
||||||
@@ -37,6 +35,9 @@ type GitCommand struct {
|
|||||||
Tag *git_commands.TagCommands
|
Tag *git_commands.TagCommands
|
||||||
WorkingTree *git_commands.WorkingTreeCommands
|
WorkingTree *git_commands.WorkingTreeCommands
|
||||||
Bisect *git_commands.BisectCommands
|
Bisect *git_commands.BisectCommands
|
||||||
|
Worktree *git_commands.WorktreeCommands
|
||||||
|
Version *git_commands.GitVersion
|
||||||
|
RepoPaths *git_commands.RepoPaths
|
||||||
|
|
||||||
Loaders Loaders
|
Loaders Loaders
|
||||||
}
|
}
|
||||||
@@ -50,6 +51,7 @@ type Loaders struct {
|
|||||||
RemoteLoader *git_commands.RemoteLoader
|
RemoteLoader *git_commands.RemoteLoader
|
||||||
StashLoader *git_commands.StashLoader
|
StashLoader *git_commands.StashLoader
|
||||||
TagLoader *git_commands.TagLoader
|
TagLoader *git_commands.TagLoader
|
||||||
|
Worktrees *git_commands.WorktreeLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGitCommand(
|
func NewGitCommand(
|
||||||
@@ -57,19 +59,25 @@ func NewGitCommand(
|
|||||||
version *git_commands.GitVersion,
|
version *git_commands.GitVersion,
|
||||||
osCommand *oscommands.OSCommand,
|
osCommand *oscommands.OSCommand,
|
||||||
gitConfig git_config.IGitConfig,
|
gitConfig git_config.IGitConfig,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) (*GitCommand, error) {
|
) (*GitCommand, error) {
|
||||||
if err := navigateToRepoRootDirectory(os.Stat, os.Chdir); err != nil {
|
repoPaths, err := git_commands.GetRepoPaths(osCommand.Cmd, version)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("Error getting repo paths: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := setupRepository(gogit.PlainOpenWithOptions, gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true}, cmn.Tr.GitconfigParseErr)
|
err = os.Chdir(repoPaths.WorktreePath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, utils.WrapError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dotGitDir, err := findDotGitDir(os.Stat, os.ReadFile)
|
repository, err := gogit.PlainOpenWithOptions(
|
||||||
|
repoPaths.WorktreeGitDirPath(),
|
||||||
|
&gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) {
|
||||||
|
return nil, errors.New(cmn.Tr.GitconfigParseErr)
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,9 +86,8 @@ func NewGitCommand(
|
|||||||
version,
|
version,
|
||||||
osCommand,
|
osCommand,
|
||||||
gitConfig,
|
gitConfig,
|
||||||
dotGitDir,
|
repoPaths,
|
||||||
repo,
|
repository,
|
||||||
syncMutex,
|
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,9 +96,8 @@ func NewGitCommandAux(
|
|||||||
version *git_commands.GitVersion,
|
version *git_commands.GitVersion,
|
||||||
osCommand *oscommands.OSCommand,
|
osCommand *oscommands.OSCommand,
|
||||||
gitConfig git_config.IGitConfig,
|
gitConfig git_config.IGitConfig,
|
||||||
dotGitDir string,
|
repoPaths *git_commands.RepoPaths,
|
||||||
repo *gogit.Repository,
|
repo *gogit.Repository,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) *GitCommand {
|
) *GitCommand {
|
||||||
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
|
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
|
||||||
|
|
||||||
@@ -102,9 +108,9 @@ func NewGitCommandAux(
|
|||||||
// common ones are: cmn, osCommand, dotGitDir, configCommands
|
// common ones are: cmn, osCommand, dotGitDir, configCommands
|
||||||
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
|
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
|
||||||
|
|
||||||
fileLoader := git_commands.NewFileLoader(cmn, cmd, configCommands)
|
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands)
|
||||||
|
|
||||||
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, dotGitDir, repo, configCommands, syncMutex)
|
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
|
||||||
statusCommands := git_commands.NewStatusCommands(gitCommon)
|
statusCommands := git_commands.NewStatusCommands(gitCommon)
|
||||||
flowCommands := git_commands.NewFlowCommands(gitCommon)
|
flowCommands := git_commands.NewFlowCommands(gitCommon)
|
||||||
remoteCommands := git_commands.NewRemoteCommands(gitCommon)
|
remoteCommands := git_commands.NewRemoteCommands(gitCommon)
|
||||||
@@ -121,22 +127,24 @@ func NewGitCommandAux(
|
|||||||
stashCommands := git_commands.NewStashCommands(gitCommon, fileLoader, workingTreeCommands)
|
stashCommands := git_commands.NewStashCommands(gitCommon, fileLoader, workingTreeCommands)
|
||||||
patchBuilder := patch.NewPatchBuilder(cmn.Log,
|
patchBuilder := patch.NewPatchBuilder(cmn.Log,
|
||||||
func(from string, to string, reverse bool, filename string, plain bool) (string, error) {
|
func(from string, to string, reverse bool, filename string, plain bool) (string, error) {
|
||||||
// TODO: make patch builder take Gui.IgnoreWhitespaceInDiffView into
|
return workingTreeCommands.ShowFileDiff(from, to, reverse, filename, plain)
|
||||||
// account. For now we just pass false.
|
|
||||||
return workingTreeCommands.ShowFileDiff(from, to, reverse, filename, plain, false)
|
|
||||||
})
|
})
|
||||||
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
|
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
|
||||||
bisectCommands := git_commands.NewBisectCommands(gitCommon)
|
bisectCommands := git_commands.NewBisectCommands(gitCommon)
|
||||||
|
worktreeCommands := git_commands.NewWorktreeCommands(gitCommon)
|
||||||
|
blameCommands := git_commands.NewBlameCommands(gitCommon)
|
||||||
|
|
||||||
branchLoader := git_commands.NewBranchLoader(cmn, cmd, branchCommands.CurrentBranchInfo, configCommands)
|
branchLoader := git_commands.NewBranchLoader(cmn, gitCommon, cmd, branchCommands.CurrentBranchInfo, configCommands)
|
||||||
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
|
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
|
||||||
commitLoader := git_commands.NewCommitLoader(cmn, cmd, dotGitDir, statusCommands.RebaseMode, gitCommon)
|
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.RebaseMode, gitCommon)
|
||||||
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
||||||
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
|
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
|
||||||
|
worktreeLoader := git_commands.NewWorktreeLoader(gitCommon)
|
||||||
stashLoader := git_commands.NewStashLoader(cmn, cmd)
|
stashLoader := git_commands.NewStashLoader(cmn, cmd)
|
||||||
tagLoader := git_commands.NewTagLoader(cmn, cmd)
|
tagLoader := git_commands.NewTagLoader(cmn, cmd)
|
||||||
|
|
||||||
return &GitCommand{
|
return &GitCommand{
|
||||||
|
Blame: blameCommands,
|
||||||
Branch: branchCommands,
|
Branch: branchCommands,
|
||||||
Commit: commitCommands,
|
Commit: commitCommands,
|
||||||
Config: configCommands,
|
Config: configCommands,
|
||||||
@@ -154,6 +162,8 @@ func NewGitCommandAux(
|
|||||||
Tag: tagCommands,
|
Tag: tagCommands,
|
||||||
Bisect: bisectCommands,
|
Bisect: bisectCommands,
|
||||||
WorkingTree: workingTreeCommands,
|
WorkingTree: workingTreeCommands,
|
||||||
|
Worktree: worktreeCommands,
|
||||||
|
Version: version,
|
||||||
Loaders: Loaders{
|
Loaders: Loaders{
|
||||||
BranchLoader: branchLoader,
|
BranchLoader: branchLoader,
|
||||||
CommitFileLoader: commitFileLoader,
|
CommitFileLoader: commitFileLoader,
|
||||||
@@ -161,121 +171,14 @@ func NewGitCommandAux(
|
|||||||
FileLoader: fileLoader,
|
FileLoader: fileLoader,
|
||||||
ReflogCommitLoader: reflogCommitLoader,
|
ReflogCommitLoader: reflogCommitLoader,
|
||||||
RemoteLoader: remoteLoader,
|
RemoteLoader: remoteLoader,
|
||||||
|
Worktrees: worktreeLoader,
|
||||||
StashLoader: stashLoader,
|
StashLoader: stashLoader,
|
||||||
TagLoader: tagLoader,
|
TagLoader: tagLoader,
|
||||||
},
|
},
|
||||||
|
RepoPaths: repoPaths,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
|
|
||||||
gitDir := env.GetGitDirEnv()
|
|
||||||
if gitDir != "" {
|
|
||||||
// we've been given the git directory explicitly so no need to navigate to it
|
|
||||||
_, err := stat(gitDir)
|
|
||||||
if err != nil {
|
|
||||||
return utils.WrapError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// we haven't been given the git dir explicitly so we assume it's in the current working directory as `.git/` (or an ancestor directory)
|
|
||||||
|
|
||||||
for {
|
|
||||||
_, err := stat(".git")
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return utils.WrapError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = chdir(".."); err != nil {
|
|
||||||
return utils.WrapError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPath, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
atRoot := currentPath == filepath.Dir(currentPath)
|
|
||||||
if atRoot {
|
|
||||||
// we should never really land here: the code that creates GitCommand should
|
|
||||||
// verify we're in a git directory
|
|
||||||
return errors.New("Must open lazygit in a git repository")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolvePath takes a path containing a symlink and returns the true path
|
|
||||||
func resolvePath(path string) (string, error) {
|
|
||||||
l, err := os.Lstat(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.Mode()&os.ModeSymlink == 0 {
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.EvalSymlinks(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupRepository(openGitRepository func(string, *gogit.PlainOpenOptions) (*gogit.Repository, error), options gogit.PlainOpenOptions, gitConfigParseErrorStr string) (*gogit.Repository, error) {
|
|
||||||
unresolvedPath := env.GetGitDirEnv()
|
|
||||||
if unresolvedPath == "" {
|
|
||||||
var err error
|
|
||||||
unresolvedPath, err = os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path, err := resolvePath(unresolvedPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
repository, err := openGitRepository(path, &options)
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) {
|
|
||||||
return nil, errors.New(gitConfigParseErrorStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return repository, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filename string) ([]byte, error)) (string, error) {
|
|
||||||
if env.GetGitDirEnv() != "" {
|
|
||||||
return env.GetGitDirEnv(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := stat(".git")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.IsDir() {
|
|
||||||
return ".git", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fileBytes, err := readFile(".git")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
fileContent := string(fileBytes)
|
|
||||||
if !strings.HasPrefix(fileContent, "gitdir: ") {
|
|
||||||
return "", errors.New(".git is a file which suggests we are in a submodule or a worktree but the file's contents do not contain a gitdir pointing to the actual .git directory")
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(strings.TrimPrefix(fileContent, "gitdir: ")), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
|
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
|
||||||
return osCommand.Cmd.New(git_commands.NewGitCmd("rev-parse").Arg("--git-dir").ToArgv()).DontLog().Run()
|
return osCommand.Cmd.New(git_commands.NewGitCmd("rev-parse").Arg("--git-dir").ToArgv()).DontLog().Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,16 @@ func NewBisectCommands(gitCommon *GitCommon) *BisectCommands {
|
|||||||
// This command is pretty cheap to run so we're not storing the result anywhere.
|
// This command is pretty cheap to run so we're not storing the result anywhere.
|
||||||
// But if it becomes problematic we can chang that.
|
// But if it becomes problematic we can chang that.
|
||||||
func (self *BisectCommands) GetInfo() *BisectInfo {
|
func (self *BisectCommands) GetInfo() *BisectInfo {
|
||||||
|
return self.GetInfoForGitDir(self.repoPaths.WorktreeGitDirPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
|
||||||
var err error
|
var err error
|
||||||
info := &BisectInfo{started: false, log: self.Log, newTerm: "bad", oldTerm: "good"}
|
info := &BisectInfo{started: false, log: self.Log, newTerm: "bad", oldTerm: "good"}
|
||||||
// we return nil if we're not in a git bisect session.
|
// we return nil if we're not in a git bisect session.
|
||||||
// we know we're in a session by the presence of a .git/BISECT_START file
|
// we know we're in a session by the presence of a .git/BISECT_START file
|
||||||
|
|
||||||
bisectStartPath := filepath.Join(self.dotGitDir, "BISECT_START")
|
bisectStartPath := filepath.Join(gitDir, "BISECT_START")
|
||||||
exists, err := self.os.FileExists(bisectStartPath)
|
exists, err := self.os.FileExists(bisectStartPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
||||||
@@ -44,7 +48,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
|
|||||||
info.started = true
|
info.started = true
|
||||||
info.start = strings.TrimSpace(string(startContent))
|
info.start = strings.TrimSpace(string(startContent))
|
||||||
|
|
||||||
termsContent, err := os.ReadFile(filepath.Join(self.dotGitDir, "BISECT_TERMS"))
|
termsContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_TERMS"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// old git versions won't have this file so we default to bad/good
|
// old git versions won't have this file so we default to bad/good
|
||||||
} else {
|
} else {
|
||||||
@@ -53,7 +57,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
|
|||||||
info.oldTerm = splitContent[1]
|
info.oldTerm = splitContent[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
bisectRefsDir := filepath.Join(self.dotGitDir, "refs", "bisect")
|
bisectRefsDir := filepath.Join(gitDir, "refs", "bisect")
|
||||||
files, err := os.ReadDir(bisectRefsDir)
|
files, err := os.ReadDir(bisectRefsDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
||||||
@@ -72,7 +76,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
|
|||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
sha := strings.TrimSpace(string(fileContent))
|
hash := strings.TrimSpace(string(fileContent))
|
||||||
|
|
||||||
if name == info.newTerm {
|
if name == info.newTerm {
|
||||||
status = BisectStatusNew
|
status = BisectStatusNew
|
||||||
@@ -82,16 +86,16 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
|
|||||||
status = BisectStatusSkipped
|
status = BisectStatusSkipped
|
||||||
}
|
}
|
||||||
|
|
||||||
info.statusMap[sha] = status
|
info.statusMap[hash] = status
|
||||||
}
|
}
|
||||||
|
|
||||||
currentContent, err := os.ReadFile(filepath.Join(self.dotGitDir, "BISECT_EXPECTED_REV"))
|
currentContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_EXPECTED_REV"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
self.Log.Infof("error getting git bisect info: %s", err.Error())
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
currentSha := strings.TrimSpace(string(currentContent))
|
currentHash := strings.TrimSpace(string(currentContent))
|
||||||
info.current = currentSha
|
info.current = currentHash
|
||||||
|
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
@@ -121,8 +125,17 @@ func (self *BisectCommands) Start() error {
|
|||||||
return self.cmd.New(cmdArgs).StreamOutput().Run()
|
return self.cmd.New(cmdArgs).StreamOutput().Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BisectCommands) StartWithTerms(oldTerm string, newTerm string) error {
|
||||||
|
cmdArgs := NewGitCmd("bisect").Arg("start").
|
||||||
|
Arg("--term-old=" + oldTerm).
|
||||||
|
Arg("--term-new=" + newTerm).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).StreamOutput().Run()
|
||||||
|
}
|
||||||
|
|
||||||
// tells us whether we've found our problem commit(s). We return a string slice of
|
// tells us whether we've found our problem commit(s). We return a string slice of
|
||||||
// commit sha's if we're done, and that slice may have more that one item if
|
// commit hashes if we're done, and that slice may have more that one item if
|
||||||
// skipped commits are involved.
|
// skipped commits are involved.
|
||||||
func (self *BisectCommands) IsDone() (bool, []string, error) {
|
func (self *BisectCommands) IsDone() (bool, []string, error) {
|
||||||
info := self.GetInfo()
|
info := self.GetInfo()
|
||||||
@@ -130,8 +143,8 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
|
|||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newSha := info.GetNewSha()
|
newHash := info.GetNewHash()
|
||||||
if newSha == "" {
|
if newHash == "" {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,14 +153,14 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
|
|||||||
done := false
|
done := false
|
||||||
candidates := []string{}
|
candidates := []string{}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("rev-list").Arg(newSha).ToArgv()
|
cmdArgs := NewGitCmd("rev-list").Arg(newHash).ToArgv()
|
||||||
err := self.cmd.New(cmdArgs).RunAndProcessLines(func(line string) (bool, error) {
|
err := self.cmd.New(cmdArgs).RunAndProcessLines(func(line string) (bool, error) {
|
||||||
sha := strings.TrimSpace(line)
|
hash := strings.TrimSpace(line)
|
||||||
|
|
||||||
if status, ok := info.statusMap[sha]; ok {
|
if status, ok := info.statusMap[hash]; ok {
|
||||||
switch status {
|
switch status {
|
||||||
case BisectStatusSkipped, BisectStatusNew:
|
case BisectStatusSkipped, BisectStatusNew:
|
||||||
candidates = append(candidates, sha)
|
candidates = append(candidates, hash)
|
||||||
return false, nil
|
return false, nil
|
||||||
case BisectStatusOld:
|
case BisectStatusOld:
|
||||||
done = true
|
done = true
|
||||||
@@ -172,7 +185,7 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
|
|||||||
// render the commits from the bad commit.
|
// render the commits from the bad commit.
|
||||||
func (self *BisectCommands) ReachableFromStart(bisectInfo *BisectInfo) bool {
|
func (self *BisectCommands) ReachableFromStart(bisectInfo *BisectInfo) bool {
|
||||||
cmdArgs := NewGitCmd("merge-base").
|
cmdArgs := NewGitCmd("merge-base").
|
||||||
Arg("--is-ancestor", bisectInfo.GetNewSha(), bisectInfo.GetStartSha()).
|
Arg("--is-ancestor", bisectInfo.GetNewHash(), bisectInfo.GetStartHash()).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
err := self.cmd.New(cmdArgs).DontLog().Run()
|
err := self.cmd.New(cmdArgs).DontLog().Run()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jesseduffield/generics/maps"
|
"github.com/jesseduffield/generics/maps"
|
||||||
"github.com/jesseduffield/generics/slices"
|
"github.com/samber/lo"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,10 +29,10 @@ type BisectInfo struct {
|
|||||||
newTerm string // 'bad' by default
|
newTerm string // 'bad' by default
|
||||||
oldTerm string // 'good' by default
|
oldTerm string // 'good' by default
|
||||||
|
|
||||||
// map of commit sha's to their status
|
// map of commit hashes to their status
|
||||||
statusMap map[string]BisectStatus
|
statusMap map[string]BisectStatus
|
||||||
|
|
||||||
// the sha of the commit that's under test
|
// the hash of the commit that's under test
|
||||||
current string
|
current string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,26 +49,26 @@ func NewNullBisectInfo() *BisectInfo {
|
|||||||
return &BisectInfo{started: false}
|
return &BisectInfo{started: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BisectInfo) GetNewSha() string {
|
func (self *BisectInfo) GetNewHash() string {
|
||||||
for sha, status := range self.statusMap {
|
for hash, status := range self.statusMap {
|
||||||
if status == BisectStatusNew {
|
if status == BisectStatusNew {
|
||||||
return sha
|
return hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BisectInfo) GetCurrentSha() string {
|
func (self *BisectInfo) GetCurrentHash() string {
|
||||||
return self.current
|
return self.current
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BisectInfo) GetStartSha() string {
|
func (self *BisectInfo) GetStartHash() string {
|
||||||
return self.start
|
return self.start
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BisectInfo) Status(commitSha string) (BisectStatus, bool) {
|
func (self *BisectInfo) Status(commitHash string) (BisectStatus, bool) {
|
||||||
status, ok := self.statusMap[commitSha]
|
status, ok := self.statusMap[commitHash]
|
||||||
return status, ok
|
return status, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,9 +93,9 @@ func (self *BisectInfo) Bisecting() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.GetNewSha() == "" {
|
if self.GetNewHash() == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return slices.Contains(maps.Values(self.statusMap), BisectStatusOld)
|
return lo.Contains(maps.Values(self.statusMap), BisectStatusOld)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package git_commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BlameCommands struct {
|
||||||
|
*GitCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlameCommands(gitCommon *GitCommon) *BlameCommands {
|
||||||
|
return &BlameCommands{
|
||||||
|
GitCommon: gitCommon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blame a range of lines. For each line, output the hash of the commit where
|
||||||
|
// the line last changed, then a space, then a description of the commit (author
|
||||||
|
// and date), another space, and then the line. For example:
|
||||||
|
//
|
||||||
|
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 11) func NewBlameCommands(gitCommon *GitCommon) *BlameCommands {
|
||||||
|
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 12) return &BlameCommands{
|
||||||
|
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 13) GitCommon: gitCommon,
|
||||||
|
func (self *BlameCommands) BlameLineRange(filename string, commit string, firstLine int, numLines int) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("blame").
|
||||||
|
Arg("-l").
|
||||||
|
Arg(fmt.Sprintf("-L%d,+%d", firstLine, numLines)).
|
||||||
|
Arg(commit).
|
||||||
|
Arg("--").
|
||||||
|
Arg(filename)
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs.ToArgv()).RunWithOutput()
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/mgutz/str"
|
"github.com/mgutz/str"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BranchCommands struct {
|
type BranchCommands struct {
|
||||||
*GitCommon
|
*GitCommon
|
||||||
|
allBranchesLogCmdIndex uint8 // keeps track of current all branches log command
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBranchCommands(gitCommon *GitCommon) *BranchCommands {
|
func NewBranchCommands(gitCommon *GitCommon) *BranchCommands {
|
||||||
@@ -28,6 +30,26 @@ func (self *BranchCommands) New(name string, base string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *BranchCommands) NewWithoutTracking(name string, base string) error {
|
||||||
|
cmdArgs := NewGitCmd("checkout").
|
||||||
|
Arg("-b", name, base).
|
||||||
|
Arg("--no-track").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateWithUpstream creates a new branch with a given upstream, but without
|
||||||
|
// checking it out
|
||||||
|
func (self *BranchCommands) CreateWithUpstream(name string, upstream string) error {
|
||||||
|
cmdArgs := NewGitCmd("branch").
|
||||||
|
Arg("--track").
|
||||||
|
Arg(name, upstream).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).Run()
|
||||||
|
}
|
||||||
|
|
||||||
// CurrentBranchInfo get the current branch information.
|
// CurrentBranchInfo get the current branch information.
|
||||||
func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
|
func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
|
||||||
branchName, err := self.cmd.New(
|
branchName, err := self.cmd.New(
|
||||||
@@ -54,10 +76,10 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
|
|||||||
for _, line := range utils.SplitLines(output) {
|
for _, line := range utils.SplitLines(output) {
|
||||||
split := strings.Split(strings.TrimRight(line, "\r\n"), "\x00")
|
split := strings.Split(strings.TrimRight(line, "\r\n"), "\x00")
|
||||||
if len(split) == 3 && split[0] == "*" {
|
if len(split) == 3 && split[0] == "*" {
|
||||||
sha := split[1]
|
hash := split[1]
|
||||||
displayName := split[2]
|
displayName := split[2]
|
||||||
return BranchInfo{
|
return BranchInfo{
|
||||||
RefName: sha,
|
RefName: hash,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
DetachedHead: true,
|
DetachedHead: true,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -70,8 +92,23 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete delete branch
|
// CurrentBranchName get name of current branch
|
||||||
func (self *BranchCommands) Delete(branch string, force bool) error {
|
func (self *BranchCommands) CurrentBranchName() (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("rev-parse").
|
||||||
|
Arg("--abbrev-ref").
|
||||||
|
Arg("--verify").
|
||||||
|
Arg("HEAD").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
|
if err == nil {
|
||||||
|
return strings.TrimSpace(output), nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalDelete delete branch locally
|
||||||
|
func (self *BranchCommands) LocalDelete(branch string, force bool) error {
|
||||||
cmdArgs := NewGitCmd("branch").
|
cmdArgs := NewGitCmd("branch").
|
||||||
ArgIfElse(force, "-D", "-d").
|
ArgIfElse(force, "-D", "-d").
|
||||||
Arg(branch).
|
Arg(branch).
|
||||||
@@ -190,13 +227,18 @@ func (self *BranchCommands) Rename(oldName string, newName string) error {
|
|||||||
|
|
||||||
type MergeOpts struct {
|
type MergeOpts struct {
|
||||||
FastForwardOnly bool
|
FastForwardOnly bool
|
||||||
|
Squash bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
|
func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
|
||||||
|
if opts.Squash && opts.FastForwardOnly {
|
||||||
|
panic("Squash and FastForwardOnly can't both be true")
|
||||||
|
}
|
||||||
cmdArgs := NewGitCmd("merge").
|
cmdArgs := NewGitCmd("merge").
|
||||||
Arg("--no-edit").
|
Arg("--no-edit").
|
||||||
ArgIf(self.UserConfig.Git.Merging.Args != "", self.UserConfig.Git.Merging.Args).
|
Arg(strings.Fields(self.UserConfig.Git.Merging.Args)...).
|
||||||
ArgIf(opts.FastForwardOnly, "--ff-only").
|
ArgIf(opts.FastForwardOnly, "--ff-only").
|
||||||
|
ArgIf(opts.Squash, "--squash", "--ff").
|
||||||
Arg(branchName).
|
Arg(branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
@@ -204,5 +246,17 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
||||||
return self.cmd.New(str.ToArgv(self.UserConfig.Git.AllBranchesLogCmd)).DontLog()
|
// Only choose between non-empty, non-identical commands
|
||||||
|
candidates := lo.Uniq(lo.WithoutEmpty(append([]string{
|
||||||
|
self.UserConfig.Git.AllBranchesLogCmd,
|
||||||
|
},
|
||||||
|
self.UserConfig.Git.AllBranchesLogCmds...,
|
||||||
|
)))
|
||||||
|
|
||||||
|
n := len(candidates)
|
||||||
|
|
||||||
|
i := self.allBranchesLogCmdIndex
|
||||||
|
self.allBranchesLogCmdIndex = uint8((int(i) + 1) % n)
|
||||||
|
|
||||||
|
return self.cmd.New(str.ToArgv(candidates[i])).DontLog()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,19 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/set"
|
"github.com/jesseduffield/generics/set"
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/go-git/v5/config"
|
"github.com/jesseduffield/go-git/v5/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
// context:
|
// context:
|
||||||
@@ -39,6 +42,7 @@ type BranchInfo struct {
|
|||||||
// BranchLoader returns a list of Branch objects for the current repo
|
// BranchLoader returns a list of Branch objects for the current repo
|
||||||
type BranchLoader struct {
|
type BranchLoader struct {
|
||||||
*common.Common
|
*common.Common
|
||||||
|
*GitCommon
|
||||||
cmd oscommands.ICmdObjBuilder
|
cmd oscommands.ICmdObjBuilder
|
||||||
getCurrentBranchInfo func() (BranchInfo, error)
|
getCurrentBranchInfo func() (BranchInfo, error)
|
||||||
config BranchLoaderConfigCommands
|
config BranchLoaderConfigCommands
|
||||||
@@ -46,12 +50,14 @@ type BranchLoader struct {
|
|||||||
|
|
||||||
func NewBranchLoader(
|
func NewBranchLoader(
|
||||||
cmn *common.Common,
|
cmn *common.Common,
|
||||||
|
gitCommon *GitCommon,
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
getCurrentBranchInfo func() (BranchInfo, error),
|
getCurrentBranchInfo func() (BranchInfo, error),
|
||||||
config BranchLoaderConfigCommands,
|
config BranchLoaderConfigCommands,
|
||||||
) *BranchLoader {
|
) *BranchLoader {
|
||||||
return &BranchLoader{
|
return &BranchLoader{
|
||||||
Common: cmn,
|
Common: cmn,
|
||||||
|
GitCommon: gitCommon,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
getCurrentBranchInfo: getCurrentBranchInfo,
|
getCurrentBranchInfo: getCurrentBranchInfo,
|
||||||
config: config,
|
config: config,
|
||||||
@@ -59,36 +65,49 @@ func NewBranchLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the list of branches for the current repo
|
// Load the list of branches for the current repo
|
||||||
func (self *BranchLoader) Load(reflogCommits []*models.Commit) ([]*models.Branch, error) {
|
func (self *BranchLoader) Load(reflogCommits []*models.Commit,
|
||||||
branches := self.obtainBranches()
|
mainBranches *MainBranches,
|
||||||
|
oldBranches []*models.Branch,
|
||||||
|
loadBehindCounts bool,
|
||||||
|
onWorker func(func() error),
|
||||||
|
renderFunc func(),
|
||||||
|
) ([]*models.Branch, error) {
|
||||||
|
branches := self.obtainBranches(self.version.IsAtLeast(2, 22, 0))
|
||||||
|
|
||||||
reflogBranches := self.obtainReflogBranches(reflogCommits)
|
if self.AppState.LocalBranchSortOrder == "recency" {
|
||||||
|
reflogBranches := self.obtainReflogBranches(reflogCommits)
|
||||||
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
|
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
|
||||||
branchesWithRecency := make([]*models.Branch, 0)
|
branchesWithRecency := make([]*models.Branch, 0)
|
||||||
outer:
|
outer:
|
||||||
for _, reflogBranch := range reflogBranches {
|
for _, reflogBranch := range reflogBranches {
|
||||||
for j, branch := range branches {
|
for j, branch := range branches {
|
||||||
if branch.Head {
|
if branch.Head {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.EqualFold(reflogBranch.Name, branch.Name) {
|
if strings.EqualFold(reflogBranch.Name, branch.Name) {
|
||||||
branch.Recency = reflogBranch.Recency
|
branch.Recency = reflogBranch.Recency
|
||||||
branchesWithRecency = append(branchesWithRecency, branch)
|
branchesWithRecency = append(branchesWithRecency, branch)
|
||||||
branches = slices.Remove(branches, j)
|
branches = utils.Remove(branches, j)
|
||||||
continue outer
|
continue outer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
branches = slices.Prepend(branches, branchesWithRecency...)
|
// Sort branches that don't have a recency value alphabetically
|
||||||
|
// (we're really doing this for the sake of deterministic behaviour across git versions)
|
||||||
|
slices.SortFunc(branches, func(a *models.Branch, b *models.Branch) bool {
|
||||||
|
return a.Name < b.Name
|
||||||
|
})
|
||||||
|
|
||||||
|
branches = utils.Prepend(branches, branchesWithRecency...)
|
||||||
|
}
|
||||||
|
|
||||||
foundHead := false
|
foundHead := false
|
||||||
for i, branch := range branches {
|
for i, branch := range branches {
|
||||||
if branch.Head {
|
if branch.Head {
|
||||||
foundHead = true
|
foundHead = true
|
||||||
branch.Recency = " *"
|
branch.Recency = " *"
|
||||||
branches = slices.Move(branches, i, 0)
|
branches = utils.Move(branches, i, 0)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +116,7 @@ outer:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
branches = slices.Prepend(branches, &models.Branch{Name: info.RefName, DisplayName: info.DisplayName, Head: true, DetachedHead: info.DetachedHead, Recency: " *"})
|
branches = utils.Prepend(branches, &models.Branch{Name: info.RefName, DisplayName: info.DisplayName, Head: true, DetachedHead: info.DetachedHead, Recency: " *"})
|
||||||
}
|
}
|
||||||
|
|
||||||
configBranches, err := self.config.Branches()
|
configBranches, err := self.config.Branches()
|
||||||
@@ -111,12 +130,109 @@ outer:
|
|||||||
branch.UpstreamRemote = match.Remote
|
branch.UpstreamRemote = match.Remote
|
||||||
branch.UpstreamBranch = match.Merge.Short()
|
branch.UpstreamBranch = match.Merge.Short()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the branch already existed, take over its BehindBaseBranch value
|
||||||
|
// to reduce flicker
|
||||||
|
if oldBranch, found := lo.Find(oldBranches, func(b *models.Branch) bool {
|
||||||
|
return b.Name == branch.Name
|
||||||
|
}); found {
|
||||||
|
branch.BehindBaseBranch.Store(oldBranch.BehindBaseBranch.Load())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if loadBehindCounts && self.UserConfig.Gui.ShowDivergenceFromBaseBranch != "none" {
|
||||||
|
onWorker(func() error {
|
||||||
|
return self.GetBehindBaseBranchValuesForAllBranches(branches, mainBranches, renderFunc)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchLoader) obtainBranches() []*models.Branch {
|
func (self *BranchLoader) GetBehindBaseBranchValuesForAllBranches(
|
||||||
|
branches []*models.Branch,
|
||||||
|
mainBranches *MainBranches,
|
||||||
|
renderFunc func(),
|
||||||
|
) error {
|
||||||
|
mainBranchRefs := mainBranches.Get()
|
||||||
|
if len(mainBranchRefs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
errg := errgroup.Group{}
|
||||||
|
|
||||||
|
for _, branch := range branches {
|
||||||
|
errg.Go(func() error {
|
||||||
|
baseBranch, err := self.GetBaseBranch(branch, mainBranches)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
behind := 0 // prime it in case something below fails
|
||||||
|
if baseBranch != "" {
|
||||||
|
output, err := self.cmd.New(
|
||||||
|
NewGitCmd("rev-list").
|
||||||
|
Arg("--left-right").
|
||||||
|
Arg("--count").
|
||||||
|
Arg(fmt.Sprintf("%s...%s", branch.FullRefName(), baseBranch)).
|
||||||
|
ToArgv(),
|
||||||
|
).DontLog().RunWithOutput()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// The format of the output is "<ahead>\t<behind>"
|
||||||
|
aheadBehindStr := strings.Split(strings.TrimSpace(output), "\t")
|
||||||
|
if len(aheadBehindStr) == 2 {
|
||||||
|
if value, err := strconv.Atoi(aheadBehindStr[1]); err == nil {
|
||||||
|
behind = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
branch.BehindBaseBranch.Store(int32(behind))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := errg.Wait()
|
||||||
|
self.Log.Debugf("time to get behind base branch values for all branches: %s", time.Since(t))
|
||||||
|
renderFunc()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the base branch for the given branch (i.e. the main branch that the
|
||||||
|
// given branch was forked off of)
|
||||||
|
//
|
||||||
|
// Note that this function may return an empty string even if the returned error
|
||||||
|
// is nil, e.g. when none of the configured main branches exist. This is not
|
||||||
|
// considered an error condition, so callers need to check both the returned
|
||||||
|
// error and whether the returned base branch is empty (and possibly react
|
||||||
|
// differently in both cases).
|
||||||
|
func (self *BranchLoader) GetBaseBranch(branch *models.Branch, mainBranches *MainBranches) (string, error) {
|
||||||
|
mergeBase := mainBranches.GetMergeBase(branch.FullRefName())
|
||||||
|
if mergeBase == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := self.cmd.New(
|
||||||
|
NewGitCmd("for-each-ref").
|
||||||
|
Arg("--contains").
|
||||||
|
Arg(mergeBase).
|
||||||
|
Arg("--format=%(refname)").
|
||||||
|
Arg(mainBranches.Get()...).
|
||||||
|
ToArgv(),
|
||||||
|
).DontLog().RunWithOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
trimmedOutput := strings.TrimSpace(output)
|
||||||
|
split := strings.Split(trimmedOutput, "\n")
|
||||||
|
if len(split) == 0 || split[0] == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return split[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *BranchLoader) obtainBranches(canUsePushTrack bool) []*models.Branch {
|
||||||
output, err := self.getRawBranches()
|
output, err := self.getRawBranches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -125,7 +241,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
|
|||||||
trimmedOutput := strings.TrimSpace(output)
|
trimmedOutput := strings.TrimSpace(output)
|
||||||
outputLines := strings.Split(trimmedOutput, "\n")
|
outputLines := strings.Split(trimmedOutput, "\n")
|
||||||
|
|
||||||
return slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) {
|
return lo.FilterMap(outputLines, func(line string, _ int) (*models.Branch, bool) {
|
||||||
if line == "" {
|
if line == "" {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -138,7 +254,8 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return obtainBranch(split), true
|
storeCommitDateAsRecency := self.AppState.LocalBranchSortOrder != "recency"
|
||||||
|
return obtainBranch(split, storeCommitDateAsRecency, canUsePushTrack), true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +267,18 @@ func (self *BranchLoader) getRawBranches() (string, error) {
|
|||||||
"%00",
|
"%00",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var sortOrder string
|
||||||
|
switch strings.ToLower(self.AppState.LocalBranchSortOrder) {
|
||||||
|
case "recency", "date":
|
||||||
|
sortOrder = "-committerdate"
|
||||||
|
case "alphabetical":
|
||||||
|
sortOrder = "refname"
|
||||||
|
default:
|
||||||
|
sortOrder = "refname"
|
||||||
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("for-each-ref").
|
cmdArgs := NewGitCmd("for-each-ref").
|
||||||
Arg("--sort=-committerdate").
|
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
|
||||||
Arg(fmt.Sprintf("--format=%s", format)).
|
Arg(fmt.Sprintf("--format=%s", format)).
|
||||||
Arg("refs/heads").
|
Arg("refs/heads").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -164,30 +291,50 @@ var branchFields = []string{
|
|||||||
"refname:short",
|
"refname:short",
|
||||||
"upstream:short",
|
"upstream:short",
|
||||||
"upstream:track",
|
"upstream:track",
|
||||||
|
"push:track",
|
||||||
"subject",
|
"subject",
|
||||||
fmt.Sprintf("objectname:short=%d", utils.COMMIT_HASH_SHORT_SIZE),
|
"objectname",
|
||||||
|
"committerdate:unix",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain branch information from parsed line output of getRawBranches()
|
// Obtain branch information from parsed line output of getRawBranches()
|
||||||
func obtainBranch(split []string) *models.Branch {
|
func obtainBranch(split []string, storeCommitDateAsRecency bool, canUsePushTrack bool) *models.Branch {
|
||||||
headMarker := split[0]
|
headMarker := split[0]
|
||||||
fullName := split[1]
|
fullName := split[1]
|
||||||
upstreamName := split[2]
|
upstreamName := split[2]
|
||||||
track := split[3]
|
track := split[3]
|
||||||
subject := split[4]
|
pushTrack := split[4]
|
||||||
commitHash := split[5]
|
subject := split[5]
|
||||||
|
commitHash := split[6]
|
||||||
|
commitDate := split[7]
|
||||||
|
|
||||||
name := strings.TrimPrefix(fullName, "heads/")
|
name := strings.TrimPrefix(fullName, "heads/")
|
||||||
pushables, pullables, gone := parseUpstreamInfo(upstreamName, track)
|
aheadForPull, behindForPull, gone := parseUpstreamInfo(upstreamName, track)
|
||||||
|
var aheadForPush, behindForPush string
|
||||||
|
if canUsePushTrack {
|
||||||
|
aheadForPush, behindForPush, _ = parseUpstreamInfo(upstreamName, pushTrack)
|
||||||
|
} else {
|
||||||
|
aheadForPush, behindForPush = aheadForPull, behindForPull
|
||||||
|
}
|
||||||
|
|
||||||
|
recency := ""
|
||||||
|
if storeCommitDateAsRecency {
|
||||||
|
if unixTimestamp, err := strconv.ParseInt(commitDate, 10, 64); err == nil {
|
||||||
|
recency = utils.UnixToTimeAgo(unixTimestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &models.Branch{
|
return &models.Branch{
|
||||||
Name: name,
|
Name: name,
|
||||||
Pushables: pushables,
|
Recency: recency,
|
||||||
Pullables: pullables,
|
AheadForPull: aheadForPull,
|
||||||
UpstreamGone: gone,
|
BehindForPull: behindForPull,
|
||||||
Head: headMarker == "*",
|
AheadForPush: aheadForPush,
|
||||||
Subject: subject,
|
BehindForPush: behindForPush,
|
||||||
CommitHash: commitHash,
|
UpstreamGone: gone,
|
||||||
|
Head: headMarker == "*",
|
||||||
|
Subject: subject,
|
||||||
|
CommitHash: commitHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,10 +350,10 @@ func parseUpstreamInfo(upstreamName string, track string) (string, string, bool)
|
|||||||
return "?", "?", true
|
return "?", "?", true
|
||||||
}
|
}
|
||||||
|
|
||||||
pushables := parseDifference(track, `ahead (\d+)`)
|
ahead := parseDifference(track, `ahead (\d+)`)
|
||||||
pullables := parseDifference(track, `behind (\d+)`)
|
behind := parseDifference(track, `behind (\d+)`)
|
||||||
|
|
||||||
return pushables, pullables, false
|
return ahead, behind, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDifference(track string, regexStr string) string {
|
func parseDifference(track string, regexStr string) string {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package git_commands
|
|||||||
|
|
||||||
// "*|feat/detect-purge|origin/feat/detect-purge|[ahead 1]"
|
// "*|feat/detect-purge|origin/feat/detect-purge|[ahead 1]"
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -10,78 +12,114 @@ import (
|
|||||||
|
|
||||||
func TestObtainBranch(t *testing.T) {
|
func TestObtainBranch(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
input []string
|
input []string
|
||||||
expectedBranch *models.Branch
|
storeCommitDateAsRecency bool
|
||||||
|
expectedBranch *models.Branch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use a time stamp of 2 1/2 hours ago, resulting in a recency string of "2h"
|
||||||
|
now := time.Now().Unix()
|
||||||
|
timeStamp := strconv.Itoa(int(now - 2.5*60*60))
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "TrimHeads",
|
testName: "TrimHeads",
|
||||||
input: []string{"", "heads/a_branch", "", "", "subject", "123"},
|
input: []string{"", "heads/a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: false,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
Pushables: "?",
|
AheadForPull: "?",
|
||||||
Pullables: "?",
|
BehindForPull: "?",
|
||||||
Head: false,
|
AheadForPush: "?",
|
||||||
Subject: "subject",
|
BehindForPush: "?",
|
||||||
CommitHash: "123",
|
Head: false,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "NoUpstream",
|
testName: "NoUpstream",
|
||||||
input: []string{"", "a_branch", "", "", "subject", "123"},
|
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: false,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
Pushables: "?",
|
AheadForPull: "?",
|
||||||
Pullables: "?",
|
BehindForPull: "?",
|
||||||
Head: false,
|
AheadForPush: "?",
|
||||||
Subject: "subject",
|
BehindForPush: "?",
|
||||||
CommitHash: "123",
|
Head: false,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "IsHead",
|
testName: "IsHead",
|
||||||
input: []string{"*", "a_branch", "", "", "subject", "123"},
|
input: []string{"*", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: false,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
Pushables: "?",
|
AheadForPull: "?",
|
||||||
Pullables: "?",
|
BehindForPull: "?",
|
||||||
Head: true,
|
AheadForPush: "?",
|
||||||
Subject: "subject",
|
BehindForPush: "?",
|
||||||
CommitHash: "123",
|
Head: true,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "IsBehindAndAhead",
|
testName: "IsBehindAndAhead",
|
||||||
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "subject", "123"},
|
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "[behind 2, ahead 3]", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: false,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
Pushables: "3",
|
AheadForPull: "3",
|
||||||
Pullables: "2",
|
BehindForPull: "2",
|
||||||
Head: false,
|
AheadForPush: "3",
|
||||||
Subject: "subject",
|
BehindForPush: "2",
|
||||||
CommitHash: "123",
|
Head: false,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "RemoteBranchIsGone",
|
testName: "RemoteBranchIsGone",
|
||||||
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "subject", "123"},
|
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "[gone]", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: false,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
UpstreamGone: true,
|
UpstreamGone: true,
|
||||||
Pushables: "?",
|
AheadForPull: "?",
|
||||||
Pullables: "?",
|
BehindForPull: "?",
|
||||||
Head: false,
|
AheadForPush: "?",
|
||||||
Subject: "subject",
|
BehindForPush: "?",
|
||||||
CommitHash: "123",
|
Head: false,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "WithCommitDateAsRecency",
|
||||||
|
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
|
storeCommitDateAsRecency: true,
|
||||||
|
expectedBranch: &models.Branch{
|
||||||
|
Name: "a_branch",
|
||||||
|
Recency: "2h",
|
||||||
|
AheadForPull: "?",
|
||||||
|
BehindForPull: "?",
|
||||||
|
AheadForPush: "?",
|
||||||
|
BehindForPush: "?",
|
||||||
|
Head: false,
|
||||||
|
Subject: "subject",
|
||||||
|
CommitHash: "123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
branch := obtainBranch(s.input)
|
branch := obtainBranch(s.input, s.storeCommitDateAsRecency, true)
|
||||||
assert.EqualValues(t, s.expectedBranch, branch)
|
assert.EqualValues(t, s.expectedBranch, branch)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ func TestBranchGetCommitDifferences(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
||||||
pushables, pullables := instance.GetCommitDifferences("HEAD", "@{u}")
|
pushables, pullables := instance.GetCommitDifferences("HEAD", "@{u}")
|
||||||
@@ -89,11 +88,10 @@ func TestBranchDeleteBranch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
||||||
|
|
||||||
s.test(instance.Delete("test", s.force))
|
s.test(instance.LocalDelete("test", s.force))
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -127,6 +125,19 @@ func TestBranchMerge(t *testing.T) {
|
|||||||
branchName: "mybranch",
|
branchName: "mybranch",
|
||||||
expected: []string{"merge", "--no-edit", "--merging-args", "mybranch"},
|
expected: []string{"merge", "--no-edit", "--merging-args", "mybranch"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testName: "multiple merging args",
|
||||||
|
userConfig: &config.UserConfig{
|
||||||
|
Git: config.GitConfig{
|
||||||
|
Merging: config.MergingConfig{
|
||||||
|
Args: "--arg1 --arg2", // it's up to the user what they put here
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
opts: MergeOpts{},
|
||||||
|
branchName: "mybranch",
|
||||||
|
expected: []string{"merge", "--no-edit", "--arg1", "--arg2", "mybranch"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
testName: "fast forward only",
|
testName: "fast forward only",
|
||||||
userConfig: &config.UserConfig{},
|
userConfig: &config.UserConfig{},
|
||||||
@@ -137,7 +148,6 @@ func TestBranchMerge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t).
|
runner := oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs(s.expected, "", nil)
|
ExpectGitArgs(s.expected, "", nil)
|
||||||
@@ -177,7 +187,6 @@ func TestBranchCheckout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.Checkout("test", CheckoutOptions{Force: s.force}))
|
s.test(instance.Checkout("test", CheckoutOptions{Force: s.force}))
|
||||||
@@ -266,7 +275,6 @@ func TestBranchCurrentBranchInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
instance := buildBranchCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.CurrentBranchInfo())
|
s.test(instance.CurrentBranchInfo())
|
||||||
|
|||||||
@@ -38,9 +38,44 @@ func (self *CommitCommands) SetAuthor(value string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a commit's coauthor using Github/Gitlab Co-authored-by metadata. Value is expected to be of the form 'Name <Email>'
|
||||||
|
func (self *CommitCommands) AddCoAuthor(hash string, author string) error {
|
||||||
|
message, err := self.GetCommitMessage(hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
message = AddCoAuthorToMessage(message, author)
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("commit").
|
||||||
|
Arg("--allow-empty", "--amend", "--only", "-m", message).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCoAuthorToMessage(message string, author string) string {
|
||||||
|
subject, body, _ := strings.Cut(message, "\n")
|
||||||
|
|
||||||
|
return strings.TrimSpace(subject) + "\n\n" + AddCoAuthorToDescription(strings.TrimSpace(body), author)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCoAuthorToDescription(description string, author string) string {
|
||||||
|
if description != "" {
|
||||||
|
lines := strings.Split(description, "\n")
|
||||||
|
if strings.HasPrefix(lines[len(lines)-1], "Co-authored-by:") {
|
||||||
|
description += "\n"
|
||||||
|
} else {
|
||||||
|
description += "\n\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return description + fmt.Sprintf("Co-authored-by: %s", author)
|
||||||
|
}
|
||||||
|
|
||||||
// ResetToCommit reset to commit
|
// ResetToCommit reset to commit
|
||||||
func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars []string) error {
|
func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars []string) error {
|
||||||
cmdArgs := NewGitCmd("reset").Arg("--"+strength, sha).ToArgv()
|
cmdArgs := NewGitCmd("reset").Arg("--"+strength, hash).ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).
|
return self.cmd.New(cmdArgs).
|
||||||
// prevents git from prompting us for input which would freeze the program
|
// prevents git from prompting us for input which would freeze the program
|
||||||
@@ -50,13 +85,13 @@ func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars [
|
|||||||
Run()
|
Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) CommitCmdObj(message string) oscommands.ICmdObj {
|
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
|
||||||
messageArgs := self.commitMessageArgs(message)
|
messageArgs := self.commitMessageArgs(summary, description)
|
||||||
|
|
||||||
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
|
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
|
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
|
||||||
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
|
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
|
||||||
Arg(messageArgs...).
|
Arg(messageArgs...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -68,9 +103,22 @@ func (self *CommitCommands) RewordLastCommitInEditorCmdObj() oscommands.ICmdObj
|
|||||||
return self.cmd.New(NewGitCmd("commit").Arg("--allow-empty", "--amend", "--only").ToArgv())
|
return self.cmd.New(NewGitCmd("commit").Arg("--allow-empty", "--amend", "--only").ToArgv())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
|
||||||
|
return self.cmd.New(NewGitCmd("commit").
|
||||||
|
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
|
||||||
|
return self.cmd.New(NewGitCmd("commit").
|
||||||
|
Arg("--edit").
|
||||||
|
Arg("--file="+tmpMessageFile).
|
||||||
|
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
|
||||||
|
ToArgv())
|
||||||
|
}
|
||||||
|
|
||||||
// RewordLastCommit rewords the topmost commit with the given message
|
// RewordLastCommit rewords the topmost commit with the given message
|
||||||
func (self *CommitCommands) RewordLastCommit(message string) error {
|
func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
|
||||||
messageArgs := self.commitMessageArgs(message)
|
messageArgs := self.commitMessageArgs(summary, description)
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
Arg("--allow-empty", "--amend", "--only").
|
Arg("--allow-empty", "--amend", "--only").
|
||||||
@@ -80,9 +128,8 @@ func (self *CommitCommands) RewordLastCommit(message string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) commitMessageArgs(message string) []string {
|
func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
|
||||||
msg, description, _ := strings.Cut(message, "\n")
|
args := []string{"-m", summary}
|
||||||
args := []string{"-m", msg}
|
|
||||||
|
|
||||||
if description != "" {
|
if description != "" {
|
||||||
args = append(args, "-m", description)
|
args = append(args, "-m", description)
|
||||||
@@ -95,7 +142,6 @@ func (self *CommitCommands) commitMessageArgs(message string) []string {
|
|||||||
func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj {
|
func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj {
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
|
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
|
||||||
ArgIf(self.verboseFlag() != "", self.verboseFlag()).
|
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs)
|
return self.cmd.New(cmdArgs)
|
||||||
@@ -109,37 +155,28 @@ func (self *CommitCommands) signoffFlag() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) verboseFlag() string {
|
func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) {
|
||||||
switch self.config.UserConfig.Git.Commit.Verbose {
|
cmdArgs := NewGitCmd("log").
|
||||||
case "always":
|
Arg("--format=%B", "--max-count=1", commitHash).
|
||||||
return "--verbose"
|
Config("log.showsignature=false").
|
||||||
case "never":
|
|
||||||
return "--no-verbose"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the subject of the HEAD commit
|
|
||||||
func (self *CommitCommands) GetHeadCommitMessage() (string, error) {
|
|
||||||
cmdArgs := NewGitCmd("log").Arg("-1", "--pretty=%s").ToArgv()
|
|
||||||
|
|
||||||
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
|
||||||
return strings.TrimSpace(message), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
|
|
||||||
cmdArgs := NewGitCmd("rev-list").
|
|
||||||
Arg("--format=%B", "--max-count=1", commitSha).
|
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
messageWithHeader, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
message := strings.Join(strings.SplitAfter(messageWithHeader, "\n")[1:], "")
|
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
|
||||||
return strings.TrimSpace(message), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitDiff(commitSha string) (string, error) {
|
func (self *CommitCommands) GetCommitSubject(commitHash string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("show").Arg("--no-color", commitSha).ToArgv()
|
cmdArgs := NewGitCmd("log").
|
||||||
|
Arg("--format=%s", "--max-count=1", commitHash).
|
||||||
|
Config("log.showsignature=false").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
subject, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
|
return strings.TrimSpace(subject), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CommitCommands) GetCommitDiff(commitHash string) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("show").Arg("--no-color", commitHash).ToArgv()
|
||||||
|
|
||||||
diff, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
diff, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
return diff, err
|
return diff, err
|
||||||
@@ -150,9 +187,9 @@ type Author struct {
|
|||||||
Email string
|
Email string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitAuthor(commitSha string) (Author, error) {
|
func (self *CommitCommands) GetCommitAuthor(commitHash string) (Author, error) {
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
Arg("--no-patch", "--pretty=format:'%an%x00%ae'", commitSha).
|
Arg("--no-patch", "--pretty=format:'%an%x00%ae'", commitHash).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
@@ -169,23 +206,37 @@ func (self *CommitCommands) GetCommitAuthor(commitSha string) (Author, error) {
|
|||||||
return author, err
|
return author, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitMessageFirstLine(sha string) (string, error) {
|
func (self *CommitCommands) GetCommitMessageFirstLine(hash string) (string, error) {
|
||||||
return self.GetCommitMessagesFirstLine([]string{sha})
|
return self.GetCommitMessagesFirstLine([]string{hash})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitMessagesFirstLine(shas []string) (string, error) {
|
func (self *CommitCommands) GetCommitMessagesFirstLine(hashes []string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
Arg("--no-patch", "--pretty=format:%s").
|
Arg("--no-patch", "--pretty=format:%s").
|
||||||
Arg(shas...).
|
Arg(hashes...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitsOneline(shas []string) (string, error) {
|
// Example output:
|
||||||
|
//
|
||||||
|
// cd50c79ae Preserve the commit message correctly even if the description has blank lines
|
||||||
|
// 3ebba5f32 Add test demonstrating a bug with preserving the commit message
|
||||||
|
// 9a423c388 Remove unused function
|
||||||
|
func (self *CommitCommands) GetHashesAndCommitMessagesFirstLine(hashes []string) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("show").
|
||||||
|
Arg("--no-patch", "--pretty=format:%h %s").
|
||||||
|
Arg(hashes...).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *CommitCommands) GetCommitsOneline(hashes []string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
Arg("--no-patch", "--oneline").
|
Arg("--no-patch", "--oneline").
|
||||||
Arg(shas...).
|
Arg(hashes...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
@@ -204,41 +255,62 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
|
|||||||
return self.cmd.New(cmdArgs)
|
return self.cmd.New(cmdArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string, ignoreWhitespace bool) oscommands.ICmdObj {
|
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
|
||||||
contextSize := self.UserConfig.Git.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
|
|
||||||
|
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
|
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
||||||
|
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
|
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
|
||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg("--stat").
|
Arg("--stat").
|
||||||
Arg("--decorate").
|
Arg("--decorate").
|
||||||
Arg("-p").
|
Arg("-p").
|
||||||
Arg(sha).
|
Arg(hash).
|
||||||
ArgIf(ignoreWhitespace, "--ignore-all-space").
|
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||||
|
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
||||||
ArgIf(filterPath != "", "--", filterPath).
|
ArgIf(filterPath != "", "--", filterPath).
|
||||||
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).DontLog()
|
return self.cmd.New(cmdArgs).DontLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert reverts the selected commit by sha
|
// Revert reverts the selected commit by hash
|
||||||
func (self *CommitCommands) Revert(sha string) error {
|
func (self *CommitCommands) Revert(hash string) error {
|
||||||
cmdArgs := NewGitCmd("revert").Arg(sha).ToArgv()
|
cmdArgs := NewGitCmd("revert").Arg(hash).ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) RevertMerge(sha string, parentNumber int) error {
|
func (self *CommitCommands) RevertMerge(hash string, parentNumber int) error {
|
||||||
cmdArgs := NewGitCmd("revert").Arg(sha, "-m", fmt.Sprintf("%d", parentNumber)).
|
cmdArgs := NewGitCmd("revert").Arg(hash, "-m", fmt.Sprintf("%d", parentNumber)).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateFixupCommit creates a commit that fixes up a previous commit
|
// CreateFixupCommit creates a commit that fixes up a previous commit
|
||||||
func (self *CommitCommands) CreateFixupCommit(sha string) error {
|
func (self *CommitCommands) CreateFixupCommit(hash string) error {
|
||||||
cmdArgs := NewGitCmd("commit").Arg("--fixup=" + sha).ToArgv()
|
cmdArgs := NewGitCmd("commit").Arg("--fixup=" + hash).ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAmendCommit creates a commit that changes the commit message of a previous commit
|
||||||
|
func (self *CommitCommands) CreateAmendCommit(originalSubject, newSubject, newDescription string, includeFileChanges bool) error {
|
||||||
|
description := newSubject
|
||||||
|
if newDescription != "" {
|
||||||
|
description += "\n\n" + newDescription
|
||||||
|
}
|
||||||
|
cmdArgs := NewGitCmd("commit").
|
||||||
|
Arg("-m", "amend! "+originalSubject).
|
||||||
|
Arg("-m", description).
|
||||||
|
ArgIf(!includeFileChanges, "--only", "--allow-empty").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
@@ -25,6 +24,7 @@ func NewCommitFileLoader(common *common.Common, cmd oscommands.ICmdObjBuilder) *
|
|||||||
// GetFilesInDiff get the specified commit files
|
// GetFilesInDiff get the specified commit files
|
||||||
func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse bool) ([]*models.CommitFile, error) {
|
func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse bool) ([]*models.CommitFile, error) {
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
Arg("--no-ext-diff").
|
Arg("--no-ext-diff").
|
||||||
Arg("--name-status").
|
Arg("--name-status").
|
||||||
@@ -52,7 +52,7 @@ func getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// typical result looks like 'A my_file' meaning my_file was added
|
// typical result looks like 'A my_file' meaning my_file was added
|
||||||
return slices.Map(lo.Chunk(lines, 2), func(chunk []string) *models.CommitFile {
|
return lo.Map(lo.Chunk(lines, 2), func(chunk []string, _ int) *models.CommitFile {
|
||||||
return &models.CommitFile{
|
return &models.CommitFile{
|
||||||
ChangeStatus: chunk[0],
|
ChangeStatus: chunk[0],
|
||||||
Name: chunk[1],
|
Name: chunk[1],
|
||||||
|
|||||||
@@ -6,16 +6,18 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// context:
|
// context:
|
||||||
@@ -33,11 +35,6 @@ type CommitLoader struct {
|
|||||||
readFile func(filename string) ([]byte, error)
|
readFile func(filename string) ([]byte, error)
|
||||||
walkFiles func(root string, fn filepath.WalkFunc) error
|
walkFiles func(root string, fn filepath.WalkFunc) error
|
||||||
dotGitDir string
|
dotGitDir string
|
||||||
// List of main branches that exist in the repo.
|
|
||||||
// We use these to obtain the merge base of the branch.
|
|
||||||
// When nil, we're yet to obtain the list of existing main branches.
|
|
||||||
// When an empty slice, we've obtained the list and it's empty.
|
|
||||||
mainBranches []string
|
|
||||||
*GitCommon
|
*GitCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +42,6 @@ type CommitLoader struct {
|
|||||||
func NewCommitLoader(
|
func NewCommitLoader(
|
||||||
cmn *common.Common,
|
cmn *common.Common,
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
dotGitDir string,
|
|
||||||
getRebaseMode func() (enums.RebaseMode, error),
|
getRebaseMode func() (enums.RebaseMode, error),
|
||||||
gitCommon *GitCommon,
|
gitCommon *GitCommon,
|
||||||
) *CommitLoader {
|
) *CommitLoader {
|
||||||
@@ -55,8 +51,6 @@ func NewCommitLoader(
|
|||||||
getRebaseMode: getRebaseMode,
|
getRebaseMode: getRebaseMode,
|
||||||
readFile: os.ReadFile,
|
readFile: os.ReadFile,
|
||||||
walkFiles: filepath.Walk,
|
walkFiles: filepath.Walk,
|
||||||
dotGitDir: dotGitDir,
|
|
||||||
mainBranches: nil,
|
|
||||||
GitCommon: gitCommon,
|
GitCommon: gitCommon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,10 +58,15 @@ func NewCommitLoader(
|
|||||||
type GetCommitsOptions struct {
|
type GetCommitsOptions struct {
|
||||||
Limit bool
|
Limit bool
|
||||||
FilterPath string
|
FilterPath string
|
||||||
|
FilterAuthor string
|
||||||
IncludeRebaseCommits bool
|
IncludeRebaseCommits bool
|
||||||
RefName string // e.g. "HEAD" or "my_branch"
|
RefName string // e.g. "HEAD" or "my_branch"
|
||||||
|
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
|
||||||
// determines if we show the whole git graph i.e. pass the '--all' flag
|
// determines if we show the whole git graph i.e. pass the '--all' flag
|
||||||
All bool
|
All bool
|
||||||
|
// If non-empty, show divergence from this ref (left-right log)
|
||||||
|
RefToShowDivergenceFrom string
|
||||||
|
MainBranches *MainBranches
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommits obtains the commits of the current branch
|
// GetCommits obtains the commits of the current branch
|
||||||
@@ -84,31 +83,81 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
|
|||||||
commits = append(commits, rebasingCommits...)
|
commits = append(commits, rebasingCommits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
var logErr error
|
||||||
|
go utils.Safe(func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
logErr = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
|
||||||
|
commit := self.extractCommitFromLine(line, opts.RefToShowDivergenceFrom != "")
|
||||||
|
commits = append(commits, commit)
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var ancestor string
|
||||||
|
var remoteAncestor string
|
||||||
|
go utils.Safe(func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
ancestor = opts.MainBranches.GetMergeBase(opts.RefName)
|
||||||
|
if opts.RefToShowDivergenceFrom != "" {
|
||||||
|
remoteAncestor = opts.MainBranches.GetMergeBase(opts.RefToShowDivergenceFrom)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
passedFirstPushedCommit := false
|
passedFirstPushedCommit := false
|
||||||
firstPushedCommit, err := self.getFirstPushedCommit(opts.RefName)
|
// I can get this before
|
||||||
|
firstPushedCommit, err := self.getFirstPushedCommit(opts.RefForPushedStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// must have no upstream branch so we'll consider everything as pushed
|
// must have no upstream branch so we'll consider everything as pushed
|
||||||
passedFirstPushedCommit = true
|
passedFirstPushedCommit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
err = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
|
wg.Wait()
|
||||||
commit := self.extractCommitFromLine(line)
|
|
||||||
if commit.Sha == firstPushedCommit {
|
if logErr != nil {
|
||||||
|
return nil, logErr
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, commit := range commits {
|
||||||
|
if commit.Hash == firstPushedCommit {
|
||||||
passedFirstPushedCommit = true
|
passedFirstPushedCommit = true
|
||||||
}
|
}
|
||||||
commit.Status = map[bool]models.CommitStatus{true: models.StatusUnpushed, false: models.StatusPushed}[!passedFirstPushedCommit]
|
if commit.Status != models.StatusRebasing {
|
||||||
commits = append(commits, commit)
|
if passedFirstPushedCommit {
|
||||||
return false, nil
|
commit.Status = models.StatusPushed
|
||||||
})
|
} else {
|
||||||
if err != nil {
|
commit.Status = models.StatusUnpushed
|
||||||
return nil, err
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(commits) == 0 {
|
if len(commits) == 0 {
|
||||||
return commits, nil
|
return commits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commits = self.setCommitMergedStatuses(opts.RefName, commits)
|
if opts.RefToShowDivergenceFrom != "" {
|
||||||
|
sort.SliceStable(commits, func(i, j int) bool {
|
||||||
|
// In the divergence view we want incoming commits to come first
|
||||||
|
return commits[i].Divergence > commits[j].Divergence
|
||||||
|
})
|
||||||
|
|
||||||
|
_, localSectionStart, found := lo.FindIndexOf(commits, func(commit *models.Commit) bool {
|
||||||
|
return commit.Divergence == models.DivergenceLeft
|
||||||
|
})
|
||||||
|
if !found {
|
||||||
|
localSectionStart = len(commits)
|
||||||
|
}
|
||||||
|
|
||||||
|
setCommitMergedStatuses(remoteAncestor, commits[:localSectionStart])
|
||||||
|
setCommitMergedStatuses(ancestor, commits[localSectionStart:])
|
||||||
|
} else {
|
||||||
|
setCommitMergedStatuses(ancestor, commits)
|
||||||
|
}
|
||||||
|
|
||||||
return commits, nil
|
return commits, nil
|
||||||
}
|
}
|
||||||
@@ -144,29 +193,39 @@ func (self *CommitLoader) MergeRebasingCommits(commits []*models.Commit) ([]*mod
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractCommitFromLine takes a line from a git log and extracts the sha, message, date, and tag if present
|
// extractCommitFromLine takes a line from a git log and extracts the hash, message, date, and tag if present
|
||||||
// then puts them into a commit object
|
// then puts them into a commit object
|
||||||
// example input:
|
// example input:
|
||||||
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
|
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
|
||||||
func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
|
func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool) *models.Commit {
|
||||||
split := strings.SplitN(line, "\x00", 7)
|
split := strings.SplitN(line, "\x00", 8)
|
||||||
|
|
||||||
sha := split[0]
|
hash := split[0]
|
||||||
unixTimestamp := split[1]
|
unixTimestamp := split[1]
|
||||||
authorName := split[2]
|
authorName := split[2]
|
||||||
authorEmail := split[3]
|
authorEmail := split[3]
|
||||||
extraInfo := strings.TrimSpace(split[4])
|
extraInfo := strings.TrimSpace(split[4])
|
||||||
parentHashes := split[5]
|
parentHashes := split[5]
|
||||||
message := split[6]
|
divergence := models.DivergenceNone
|
||||||
|
if showDivergence {
|
||||||
|
divergence = lo.Ternary(split[6] == "<", models.DivergenceLeft, models.DivergenceRight)
|
||||||
|
}
|
||||||
|
message := split[7]
|
||||||
|
|
||||||
tags := []string{}
|
tags := []string{}
|
||||||
|
|
||||||
if extraInfo != "" {
|
if extraInfo != "" {
|
||||||
re := regexp.MustCompile(`tag: ([^,\)]+)`)
|
extraInfoFields := strings.Split(extraInfo, ",")
|
||||||
tagMatch := re.FindStringSubmatch(extraInfo)
|
for _, extraInfoField := range extraInfoFields {
|
||||||
if len(tagMatch) > 1 {
|
extraInfoField = strings.TrimSpace(extraInfoField)
|
||||||
tags = append(tags, tagMatch[1])
|
re := regexp.MustCompile(`tag: (.+)`)
|
||||||
|
tagMatch := re.FindStringSubmatch(extraInfoField)
|
||||||
|
if len(tagMatch) > 1 {
|
||||||
|
tags = append(tags, tagMatch[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraInfo = "(" + extraInfo + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
unitTimestampInt, _ := strconv.Atoi(unixTimestamp)
|
unitTimestampInt, _ := strconv.Atoi(unixTimestamp)
|
||||||
@@ -177,7 +236,7 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &models.Commit{
|
return &models.Commit{
|
||||||
Sha: sha,
|
Hash: hash,
|
||||||
Name: message,
|
Name: message,
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
ExtraInfo: extraInfo,
|
ExtraInfo: extraInfo,
|
||||||
@@ -185,21 +244,19 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
|
|||||||
AuthorName: authorName,
|
AuthorName: authorName,
|
||||||
AuthorEmail: authorEmail,
|
AuthorEmail: authorEmail,
|
||||||
Parents: parents,
|
Parents: parents,
|
||||||
|
Divergence: divergence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
|
func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
|
||||||
commits, err := self.getRebasingCommits(rebaseMode)
|
commits := self.getRebasingCommits(rebaseMode)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(commits) == 0 {
|
if len(commits) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commitShas := slices.FilterMap(commits, func(commit *models.Commit) (string, bool) {
|
commitHashes := lo.FilterMap(commits, func(commit *models.Commit, _ int) (string, bool) {
|
||||||
return commit.Sha, commit.Sha != ""
|
return commit.Hash, commit.Hash != ""
|
||||||
})
|
})
|
||||||
|
|
||||||
// note that we're not filtering these as we do non-rebasing commits just because
|
// note that we're not filtering these as we do non-rebasing commits just because
|
||||||
@@ -208,14 +265,14 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
|
|||||||
NewGitCmd("show").
|
NewGitCmd("show").
|
||||||
Config("log.showSignature=false").
|
Config("log.showSignature=false").
|
||||||
Arg("--no-patch", "--oneline", "--abbrev=20", prettyFormat).
|
Arg("--no-patch", "--oneline", "--abbrev=20", prettyFormat).
|
||||||
Arg(commitShas...).
|
Arg(commitHashes...).
|
||||||
ToArgv(),
|
ToArgv(),
|
||||||
).DontLog()
|
).DontLog()
|
||||||
|
|
||||||
fullCommits := map[string]*models.Commit{}
|
fullCommits := map[string]*models.Commit{}
|
||||||
err = cmdObj.RunAndProcessLines(func(line string) (bool, error) {
|
err := cmdObj.RunAndProcessLines(func(line string) (bool, error) {
|
||||||
commit := self.extractCommitFromLine(line)
|
commit := self.extractCommitFromLine(line, false)
|
||||||
fullCommits[commit.Sha] = commit
|
fullCommits[commit.Hash] = commit
|
||||||
return false, nil
|
return false, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -223,23 +280,23 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
findFullCommit := lo.Ternary(self.version.IsOlderThan(2, 25, 2),
|
findFullCommit := lo.Ternary(self.version.IsOlderThan(2, 25, 2),
|
||||||
func(sha string) *models.Commit {
|
func(hash string) *models.Commit {
|
||||||
for s, c := range fullCommits {
|
for s, c := range fullCommits {
|
||||||
if strings.HasPrefix(s, sha) {
|
if strings.HasPrefix(s, hash) {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func(sha string) *models.Commit {
|
func(hash string) *models.Commit {
|
||||||
return fullCommits[sha]
|
return fullCommits[hash]
|
||||||
})
|
})
|
||||||
|
|
||||||
hydratedCommits := make([]*models.Commit, 0, len(commits))
|
hydratedCommits := make([]*models.Commit, 0, len(commits))
|
||||||
for _, rebasingCommit := range commits {
|
for _, rebasingCommit := range commits {
|
||||||
if rebasingCommit.Sha == "" {
|
if rebasingCommit.Hash == "" {
|
||||||
hydratedCommits = append(hydratedCommits, rebasingCommit)
|
hydratedCommits = append(hydratedCommits, rebasingCommit)
|
||||||
} else if commit := findFullCommit(rebasingCommit.Sha); commit != nil {
|
} else if commit := findFullCommit(rebasingCommit.Hash); commit != nil {
|
||||||
commit.Action = rebasingCommit.Action
|
commit.Action = rebasingCommit.Action
|
||||||
commit.Status = rebasingCommit.Status
|
commit.Status = rebasingCommit.Status
|
||||||
hydratedCommits = append(hydratedCommits, commit)
|
hydratedCommits = append(hydratedCommits, commit)
|
||||||
@@ -249,73 +306,20 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getRebasingCommits obtains the commits that we're in the process of rebasing
|
// getRebasingCommits obtains the commits that we're in the process of rebasing
|
||||||
func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
|
|
||||||
switch rebaseMode {
|
|
||||||
case enums.REBASE_MODE_MERGING:
|
|
||||||
return self.getNormalRebasingCommits()
|
|
||||||
case enums.REBASE_MODE_INTERACTIVE:
|
|
||||||
return self.getInteractiveRebasingCommits()
|
|
||||||
default:
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *CommitLoader) getNormalRebasingCommits() ([]*models.Commit, error) {
|
|
||||||
rewrittenCount := 0
|
|
||||||
bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-apply/rewritten"))
|
|
||||||
if err == nil {
|
|
||||||
content := string(bytesContent)
|
|
||||||
rewrittenCount = len(strings.Split(content, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// we know we're rebasing, so lets get all the files whose names have numbers
|
|
||||||
commits := []*models.Commit{}
|
|
||||||
err = self.walkFiles(filepath.Join(self.dotGitDir, "rebase-apply"), func(path string, f os.FileInfo, err error) error {
|
|
||||||
if rewrittenCount > 0 {
|
|
||||||
rewrittenCount--
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
re := regexp.MustCompile(`^\d+$`)
|
|
||||||
if !re.MatchString(f.Name()) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
bytesContent, err := self.readFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
content := string(bytesContent)
|
|
||||||
commit := self.commitFromPatch(content)
|
|
||||||
commits = append([]*models.Commit{commit}, commits...)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return commits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// git-rebase-todo example:
|
// git-rebase-todo example:
|
||||||
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 ac446ae
|
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 ac446ae
|
||||||
// pick afb893148791a2fbd8091aeb81deba4930c73031 afb8931
|
// pick afb893148791a2fbd8091aeb81deba4930c73031 afb8931
|
||||||
|
func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) []*models.Commit {
|
||||||
|
if rebaseMode != enums.REBASE_MODE_INTERACTIVE {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// git-rebase-todo.backup example:
|
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
|
||||||
// pick 49cbba374296938ea86bbd4bf4fee2f6ba5cccf6 third commit on master
|
|
||||||
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 blah commit on master
|
|
||||||
// pick afb893148791a2fbd8091aeb81deba4930c73031 fourth commit on master
|
|
||||||
|
|
||||||
// getInteractiveRebasingCommits takes our git-rebase-todo and our git-rebase-todo.backup files
|
|
||||||
// and extracts out the sha and names of commits that we still have to go
|
|
||||||
// in the rebase:
|
|
||||||
func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, error) {
|
|
||||||
bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Error(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
|
self.Log.Error(fmt.Sprintf("error occurred reading git-rebase-todo: %s", err.Error()))
|
||||||
// we assume an error means the file doesn't exist so we just return
|
// we assume an error means the file doesn't exist so we just return
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commits := []*models.Commit{}
|
commits := []*models.Commit{}
|
||||||
@@ -323,14 +327,14 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err
|
|||||||
todos, err := todo.Parse(bytes.NewBuffer(bytesContent), self.config.GetCoreCommentChar())
|
todos, err := todo.Parse(bytes.NewBuffer(bytesContent), self.config.GetCoreCommentChar())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Error(fmt.Sprintf("error occurred while parsing git-rebase-todo file: %s", err.Error()))
|
self.Log.Error(fmt.Sprintf("error occurred while parsing git-rebase-todo file: %s", err.Error()))
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if the current commit couldn't be applied because it conflicted; if
|
// See if the current commit couldn't be applied because it conflicted; if
|
||||||
// so, add a fake entry for it
|
// so, add a fake entry for it
|
||||||
if conflictedCommitSha := self.getConflictedCommit(todos); conflictedCommitSha != "" {
|
if conflictedCommitHash := self.getConflictedCommit(todos); conflictedCommitHash != "" {
|
||||||
commits = append(commits, &models.Commit{
|
commits = append(commits, &models.Commit{
|
||||||
Sha: conflictedCommitSha,
|
Hash: conflictedCommitHash,
|
||||||
Name: "",
|
Name: "",
|
||||||
Status: models.StatusRebasing,
|
Status: models.StatusRebasing,
|
||||||
Action: models.ActionConflict,
|
Action: models.ActionConflict,
|
||||||
@@ -339,24 +343,26 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err
|
|||||||
|
|
||||||
for _, t := range todos {
|
for _, t := range todos {
|
||||||
if t.Command == todo.UpdateRef {
|
if t.Command == todo.UpdateRef {
|
||||||
t.Msg = strings.TrimPrefix(t.Ref, "refs/heads/")
|
t.Msg = t.Ref
|
||||||
|
} else if t.Command == todo.Exec {
|
||||||
|
t.Msg = t.ExecCommand
|
||||||
} else if t.Commit == "" {
|
} else if t.Commit == "" {
|
||||||
// Command does not have a commit associated, skip
|
// Command does not have a commit associated, skip
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
commits = slices.Prepend(commits, &models.Commit{
|
commits = utils.Prepend(commits, &models.Commit{
|
||||||
Sha: t.Commit,
|
Hash: t.Commit,
|
||||||
Name: t.Msg,
|
Name: t.Msg,
|
||||||
Status: models.StatusRebasing,
|
Status: models.StatusRebasing,
|
||||||
Action: t.Command,
|
Action: t.Command,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return commits, nil
|
return commits
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
|
func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
|
||||||
bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-merge/done"))
|
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/done"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Log.Error(fmt.Sprintf("error occurred reading rebase-merge/done: %s", err.Error()))
|
self.Log.Error(fmt.Sprintf("error occurred reading rebase-merge/done: %s", err.Error()))
|
||||||
return ""
|
return ""
|
||||||
@@ -369,7 +375,7 @@ func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
amendFileExists := false
|
amendFileExists := false
|
||||||
if _, err := os.Stat(filepath.Join(self.dotGitDir, "rebase-merge/amend")); err == nil {
|
if _, err := os.Stat(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/amend")); err == nil {
|
||||||
amendFileExists = true
|
amendFileExists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,30 +448,15 @@ func (self *CommitLoader) getConflictedCommitImpl(todos []todo.Todo, doneTodos [
|
|||||||
return lastTodo.Commit
|
return lastTodo.Commit
|
||||||
}
|
}
|
||||||
|
|
||||||
// assuming the file starts like this:
|
func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
|
||||||
// From e93d4193e6dd45ca9cf3a5a273d7ba6cd8b8fb20 Mon Sep 17 00:00:00 2001
|
|
||||||
// From: Lazygit Tester <test@example.com>
|
|
||||||
// Date: Wed, 5 Dec 2018 21:03:23 +1100
|
|
||||||
// Subject: second commit on master
|
|
||||||
func (self *CommitLoader) commitFromPatch(content string) *models.Commit {
|
|
||||||
lines := strings.Split(content, "\n")
|
|
||||||
sha := strings.Split(lines[0], " ")[1]
|
|
||||||
name := strings.TrimPrefix(lines[3], "Subject: ")
|
|
||||||
return &models.Commit{
|
|
||||||
Sha: sha,
|
|
||||||
Name: name,
|
|
||||||
Status: models.StatusRebasing,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *CommitLoader) setCommitMergedStatuses(refName string, commits []*models.Commit) []*models.Commit {
|
|
||||||
ancestor := self.getMergeBase(refName)
|
|
||||||
if ancestor == "" {
|
if ancestor == "" {
|
||||||
return commits
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
passedAncestor := false
|
passedAncestor := false
|
||||||
for i, commit := range commits {
|
for i, commit := range commits {
|
||||||
if strings.HasPrefix(ancestor, commit.Sha) {
|
// some commits aren't really commits and don't have hashes, such as the update-ref todo
|
||||||
|
if commit.Hash != "" && strings.HasPrefix(ancestor, commit.Hash) {
|
||||||
passedAncestor = true
|
passedAncestor = true
|
||||||
}
|
}
|
||||||
if commit.Status != models.StatusPushed && commit.Status != models.StatusUnpushed {
|
if commit.Status != models.StatusPushed && commit.Status != models.StatusUnpushed {
|
||||||
@@ -475,65 +466,6 @@ func (self *CommitLoader) setCommitMergedStatuses(refName string, commits []*mod
|
|||||||
commits[i].Status = models.StatusMerged
|
commits[i].Status = models.StatusMerged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return commits
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *CommitLoader) getMergeBase(refName string) string {
|
|
||||||
if self.mainBranches == nil {
|
|
||||||
self.mainBranches = self.getExistingMainBranches()
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(self.mainBranches) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// We pass all configured main branches to the merge-base call; git will
|
|
||||||
// return the base commit for the closest one.
|
|
||||||
|
|
||||||
output, err := self.cmd.New(
|
|
||||||
NewGitCmd("merge-base").Arg(refName).Arg(self.mainBranches...).
|
|
||||||
ToArgv(),
|
|
||||||
).DontLog().RunWithOutput()
|
|
||||||
if err != nil {
|
|
||||||
// If there's an error, it must be because one of the main branches that
|
|
||||||
// used to exist when we called getExistingMainBranches() was deleted
|
|
||||||
// meanwhile. To fix this for next time, throw away our cache.
|
|
||||||
self.mainBranches = nil
|
|
||||||
}
|
|
||||||
return ignoringWarnings(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *CommitLoader) getExistingMainBranches() []string {
|
|
||||||
return lo.FilterMap(self.UserConfig.Git.MainBranches,
|
|
||||||
func(branchName string, _ int) (string, bool) {
|
|
||||||
// Try to determine upstream of local main branch
|
|
||||||
if ref, err := self.cmd.New(
|
|
||||||
NewGitCmd("rev-parse").Arg("--symbolic-full-name", branchName+"@{u}").ToArgv(),
|
|
||||||
).DontLog().RunWithOutput(); err == nil {
|
|
||||||
return strings.TrimSpace(ref), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this failed, a local branch for this main branch doesn't exist or it
|
|
||||||
// has no upstream configured. Try looking for one in the "origin" remote.
|
|
||||||
ref := "refs/remotes/origin/" + branchName
|
|
||||||
if err := self.cmd.New(
|
|
||||||
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
|
|
||||||
).DontLog().Run(); err == nil {
|
|
||||||
return ref, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this failed as well, try if we have the main branch as a local
|
|
||||||
// branch. This covers the case where somebody is using git locally
|
|
||||||
// for something, but never pushing anywhere.
|
|
||||||
ref = "refs/heads/" + branchName
|
|
||||||
if err := self.cmd.New(
|
|
||||||
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
|
|
||||||
).DontLog().Run(); err == nil {
|
|
||||||
return ref, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ignoringWarnings(commandOutput string) string {
|
func ignoringWarnings(commandOutput string) string {
|
||||||
@@ -546,7 +478,7 @@ func ignoringWarnings(commandOutput string) string {
|
|||||||
return lastLine
|
return lastLine
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFirstPushedCommit returns the first commit SHA which has been pushed to the ref's upstream.
|
// getFirstPushedCommit returns the first commit hash which has been pushed to the ref's upstream.
|
||||||
// all commits above this are deemed unpushed and marked as such.
|
// all commits above this are deemed unpushed and marked as such.
|
||||||
func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
|
func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
|
||||||
output, err := self.cmd.New(
|
output, err := self.cmd.New(
|
||||||
@@ -566,18 +498,25 @@ func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
|
|||||||
|
|
||||||
// getLog gets the git log.
|
// getLog gets the git log.
|
||||||
func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
|
func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
|
||||||
config := self.UserConfig.Git.Log
|
gitLogOrder := self.AppState.GitLogOrder
|
||||||
|
|
||||||
|
refSpec := opts.RefName
|
||||||
|
if opts.RefToShowDivergenceFrom != "" {
|
||||||
|
refSpec += "..." + opts.RefToShowDivergenceFrom
|
||||||
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
Arg(opts.RefName).
|
Arg(refSpec).
|
||||||
ArgIf(config.Order != "default", "--"+config.Order).
|
ArgIf(gitLogOrder != "default", "--"+gitLogOrder).
|
||||||
ArgIf(opts.All, "--all").
|
ArgIf(opts.All, "--all").
|
||||||
Arg("--oneline").
|
Arg("--oneline").
|
||||||
Arg(prettyFormat).
|
Arg(prettyFormat).
|
||||||
Arg("--abbrev=40").
|
Arg("--abbrev=40").
|
||||||
|
ArgIf(opts.FilterAuthor != "", "--author="+opts.FilterAuthor).
|
||||||
ArgIf(opts.Limit, "-300").
|
ArgIf(opts.Limit, "-300").
|
||||||
ArgIf(opts.FilterPath != "", "--follow").
|
ArgIf(opts.FilterPath != "", "--follow").
|
||||||
Arg("--no-show-signature").
|
Arg("--no-show-signature").
|
||||||
|
ArgIf(opts.RefToShowDivergenceFrom != "", "--left-right").
|
||||||
Arg("--").
|
Arg("--").
|
||||||
ArgIf(opts.FilterPath != "", opts.FilterPath).
|
ArgIf(opts.FilterPath != "", opts.FilterPath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -585,4 +524,4 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
|
|||||||
return self.cmd.New(cmdArgs).DontLog()
|
return self.cmd.New(cmdArgs).DontLog()
|
||||||
}
|
}
|
||||||
|
|
||||||
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s`
|
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s`
|
||||||
|
|||||||
@@ -1,29 +1,30 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var commitsOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode
|
var commitsOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode
|
||||||
b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield|jessedduffield@gmail.com| (origin/better-tests)|e94e8fc5b6fab4cb755f|fix logging
|
b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield|jessedduffield@gmail.com|origin/better-tests|e94e8fc5b6fab4cb755f|>|fix logging
|
||||||
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield|jessedduffield@gmail.com||d8084cd558925eb7c9c3|refactor
|
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield|jessedduffield@gmail.com|tag: 123, tag: 456|d8084cd558925eb7c9c3|>|refactor
|
||||||
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|WIP
|
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|>|WIP
|
||||||
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|WIP
|
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|>|WIP
|
||||||
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|WIP
|
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|>|WIP
|
||||||
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|WIP
|
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|>|WIP
|
||||||
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|refactoring the config struct`, "|", "\x00", -1)
|
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|>|refactoring the config struct`, "|", "\x00", -1)
|
||||||
|
|
||||||
var singleCommitOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode`, "|", "\x00", -1)
|
var singleCommitOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode`, "|", "\x00", -1)
|
||||||
|
|
||||||
func TestGetCommits(t *testing.T) {
|
func TestGetCommits(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
@@ -42,10 +43,10 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should return no commits if there are none",
|
testName: "should return no commits if there are none",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
|
||||||
expectedCommits: []*models.Commit{},
|
expectedCommits: []*models.Commit{},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
@@ -54,10 +55,10 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should use proper upstream name for branch",
|
testName: "should use proper upstream name for branch",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "refs/heads/mybranch", IncludeRebaseCommits: false},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
|
||||||
expectedCommits: []*models.Commit{},
|
expectedCommits: []*models.Commit{},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
@@ -66,13 +67,13 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should return commits if they are present",
|
testName: "should return commits if they are present",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main", "develop"},
|
mainBranches: []string{"master", "main", "develop"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
// here it's seeing which commits are yet to be pushed
|
// here it's seeing which commits are yet to be pushed
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
// here it's actually getting all the commits in a formatted form, one per line
|
// here it's actually getting all the commits in a formatted form, one per line
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
|
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
|
||||||
// here it's testing which of the configured main branches have an upstream
|
// here it's testing which of the configured main branches have an upstream
|
||||||
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil). // this one does
|
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil). // this one does
|
||||||
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")). // this one doesn't, so it checks origin instead
|
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")). // this one doesn't, so it checks origin instead
|
||||||
@@ -85,7 +86,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
|
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
||||||
Name: "better typing for rebase mode",
|
Name: "better typing for rebase mode",
|
||||||
Status: models.StatusUnpushed,
|
Status: models.StatusUnpushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -99,7 +100,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
|
Hash: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
|
||||||
Name: "fix logging",
|
Name: "fix logging",
|
||||||
Status: models.StatusPushed,
|
Status: models.StatusPushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -113,12 +114,12 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
|
Hash: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
|
||||||
Name: "refactor",
|
Name: "refactor",
|
||||||
Status: models.StatusPushed,
|
Status: models.StatusPushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
Tags: []string{},
|
Tags: []string{"123", "456"},
|
||||||
ExtraInfo: "",
|
ExtraInfo: "(tag: 123, tag: 456)",
|
||||||
AuthorName: "Jesse Duffield",
|
AuthorName: "Jesse Duffield",
|
||||||
AuthorEmail: "jessedduffield@gmail.com",
|
AuthorEmail: "jessedduffield@gmail.com",
|
||||||
UnixTimestamp: 1640823749,
|
UnixTimestamp: 1640823749,
|
||||||
@@ -127,7 +128,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "d8084cd558925eb7c9c38afeed5725c21653ab90",
|
Hash: "d8084cd558925eb7c9c38afeed5725c21653ab90",
|
||||||
Name: "WIP",
|
Name: "WIP",
|
||||||
Status: models.StatusPushed,
|
Status: models.StatusPushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -141,7 +142,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
|
Hash: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
|
||||||
Name: "WIP",
|
Name: "WIP",
|
||||||
Status: models.StatusPushed,
|
Status: models.StatusPushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -155,7 +156,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
|
Hash: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
|
||||||
Name: "WIP",
|
Name: "WIP",
|
||||||
Status: models.StatusMerged,
|
Status: models.StatusMerged,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -169,7 +170,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
|
Hash: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
|
||||||
Name: "WIP",
|
Name: "WIP",
|
||||||
Status: models.StatusMerged,
|
Status: models.StatusMerged,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -183,7 +184,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
|
Hash: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
|
||||||
Name: "refactoring the config struct",
|
Name: "refactoring the config struct",
|
||||||
Status: models.StatusMerged,
|
Status: models.StatusMerged,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -203,13 +204,13 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should not call merge-base for mainBranches if none exist",
|
testName: "should not call merge-base for mainBranches if none exist",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main"},
|
mainBranches: []string{"master", "main"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
// here it's seeing which commits are yet to be pushed
|
// here it's seeing which commits are yet to be pushed
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
// here it's actually getting all the commits in a formatted form, one per line
|
// here it's actually getting all the commits in a formatted form, one per line
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
|
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
|
||||||
// here it's testing which of the configured main branches exist; neither does
|
// here it's testing which of the configured main branches exist; neither does
|
||||||
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "", errors.New("error")).
|
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "", errors.New("error")).
|
||||||
ExpectGitArgs([]string{"rev-parse", "--verify", "--quiet", "refs/remotes/origin/master"}, "", errors.New("error")).
|
ExpectGitArgs([]string{"rev-parse", "--verify", "--quiet", "refs/remotes/origin/master"}, "", errors.New("error")).
|
||||||
@@ -220,7 +221,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
|
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
||||||
Name: "better typing for rebase mode",
|
Name: "better typing for rebase mode",
|
||||||
Status: models.StatusUnpushed,
|
Status: models.StatusUnpushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -240,13 +241,13 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should call merge-base for all main branches that exist",
|
testName: "should call merge-base for all main branches that exist",
|
||||||
logOrder: "topo-order",
|
logOrder: "topo-order",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
mainBranches: []string{"master", "main", "develop", "1.0-hotfixes"},
|
mainBranches: []string{"master", "main", "develop", "1.0-hotfixes"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
// here it's seeing which commits are yet to be pushed
|
// here it's seeing which commits are yet to be pushed
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
// here it's actually getting all the commits in a formatted form, one per line
|
// here it's actually getting all the commits in a formatted form, one per line
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
|
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
|
||||||
// here it's testing which of the configured main branches exist
|
// here it's testing which of the configured main branches exist
|
||||||
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil).
|
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "master@{u}"}, "refs/remotes/origin/master", nil).
|
||||||
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")).
|
ExpectGitArgs([]string{"rev-parse", "--symbolic-full-name", "main@{u}"}, "", errors.New("error")).
|
||||||
@@ -259,7 +260,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
|
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
|
||||||
Name: "better typing for rebase mode",
|
Name: "better typing for rebase mode",
|
||||||
Status: models.StatusUnpushed,
|
Status: models.StatusUnpushed,
|
||||||
Action: models.ActionNone,
|
Action: models.ActionNone,
|
||||||
@@ -279,10 +280,10 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should not specify order if `log.order` is `default`",
|
testName: "should not specify order if `log.order` is `default`",
|
||||||
logOrder: "default",
|
logOrder: "default",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
|
||||||
|
|
||||||
expectedCommits: []*models.Commit{},
|
expectedCommits: []*models.Commit{},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
@@ -291,10 +292,10 @@ func TestGetCommits(t *testing.T) {
|
|||||||
testName: "should set filter path",
|
testName: "should set filter path",
|
||||||
logOrder: "default",
|
logOrder: "default",
|
||||||
rebaseMode: enums.REBASE_MODE_NONE,
|
rebaseMode: enums.REBASE_MODE_NONE,
|
||||||
opts: GetCommitsOptions{RefName: "HEAD", FilterPath: "src"},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
|
||||||
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%d%x00%p%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
|
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
|
||||||
|
|
||||||
expectedCommits: []*models.Commit{},
|
expectedCommits: []*models.Commit{},
|
||||||
expectedError: nil,
|
expectedError: nil,
|
||||||
@@ -302,14 +303,15 @@ func TestGetCommits(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
scenario := scenario
|
|
||||||
t.Run(scenario.testName, func(t *testing.T) {
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
common := utils.NewDummyCommon()
|
common := utils.NewDummyCommon()
|
||||||
common.UserConfig.Git.Log.Order = scenario.logOrder
|
common.AppState = &config.AppState{}
|
||||||
|
common.AppState.GitLogOrder = scenario.logOrder
|
||||||
|
cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner)
|
||||||
|
|
||||||
builder := &CommitLoader{
|
builder := &CommitLoader{
|
||||||
Common: common,
|
Common: common,
|
||||||
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
|
cmd: cmd,
|
||||||
getRebaseMode: func() (enums.RebaseMode, error) { return scenario.rebaseMode, nil },
|
getRebaseMode: func() (enums.RebaseMode, error) { return scenario.rebaseMode, nil },
|
||||||
dotGitDir: ".git",
|
dotGitDir: ".git",
|
||||||
readFile: func(filename string) ([]byte, error) {
|
readFile: func(filename string) ([]byte, error) {
|
||||||
@@ -321,7 +323,9 @@ func TestGetCommits(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
common.UserConfig.Git.MainBranches = scenario.mainBranches
|
common.UserConfig.Git.MainBranches = scenario.mainBranches
|
||||||
commits, err := builder.GetCommits(scenario.opts)
|
opts := scenario.opts
|
||||||
|
opts.MainBranches = NewMainBranches(scenario.mainBranches, cmd)
|
||||||
|
commits, err := builder.GetCommits(opts)
|
||||||
|
|
||||||
assert.Equal(t, scenario.expectedCommits, commits)
|
assert.Equal(t, scenario.expectedCommits, commits)
|
||||||
assert.Equal(t, scenario.expectedError, err)
|
assert.Equal(t, scenario.expectedError, err)
|
||||||
@@ -337,14 +341,14 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
todos []todo.Todo
|
todos []todo.Todo
|
||||||
doneTodos []todo.Todo
|
doneTodos []todo.Todo
|
||||||
amendFileExists bool
|
amendFileExists bool
|
||||||
expectedSha string
|
expectedHash string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
testName: "no done todos",
|
testName: "no done todos",
|
||||||
todos: []todo.Todo{},
|
todos: []todo.Todo{},
|
||||||
doneTodos: []todo.Todo{},
|
doneTodos: []todo.Todo{},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "common case (conflict)",
|
testName: "common case (conflict)",
|
||||||
@@ -360,7 +364,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "fa1afe1",
|
expectedHash: "fa1afe1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "last command was 'break'",
|
testName: "last command was 'break'",
|
||||||
@@ -369,7 +373,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
{Command: todo.Break},
|
{Command: todo.Break},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "last command was 'exec'",
|
testName: "last command was 'exec'",
|
||||||
@@ -381,7 +385,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "last command was 'reword'",
|
testName: "last command was 'reword'",
|
||||||
@@ -390,7 +394,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
{Command: todo.Reword},
|
{Command: todo.Reword},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "'pick' was rescheduled",
|
testName: "'pick' was rescheduled",
|
||||||
@@ -407,7 +411,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "'pick' was rescheduled, buggy git version",
|
testName: "'pick' was rescheduled, buggy git version",
|
||||||
@@ -432,7 +436,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "conflicting 'pick' after 'exec'",
|
testName: "conflicting 'pick' after 'exec'",
|
||||||
@@ -457,7 +461,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "fa1afe1",
|
expectedHash: "fa1afe1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "'edit' with amend file",
|
testName: "'edit' with amend file",
|
||||||
@@ -469,7 +473,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: true,
|
amendFileExists: true,
|
||||||
expectedSha: "",
|
expectedHash: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "'edit' without amend file",
|
testName: "'edit' without amend file",
|
||||||
@@ -481,7 +485,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
amendFileExists: false,
|
amendFileExists: false,
|
||||||
expectedSha: "fa1afe1",
|
expectedHash: "fa1afe1",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
@@ -501,8 +505,56 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sha := builder.getConflictedCommitImpl(scenario.todos, scenario.doneTodos, scenario.amendFileExists)
|
hash := builder.getConflictedCommitImpl(scenario.todos, scenario.doneTodos, scenario.amendFileExists)
|
||||||
assert.Equal(t, scenario.expectedSha, sha)
|
assert.Equal(t, scenario.expectedHash, hash)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitLoader_setCommitMergedStatuses(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
commits []*models.Commit
|
||||||
|
ancestor string
|
||||||
|
expectedCommits []*models.Commit
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
testName: "basic",
|
||||||
|
commits: []*models.Commit{
|
||||||
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
|
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
|
},
|
||||||
|
ancestor: "67890",
|
||||||
|
expectedCommits: []*models.Commit{
|
||||||
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
|
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusMerged},
|
||||||
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusMerged},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "with update-ref",
|
||||||
|
commits: []*models.Commit{
|
||||||
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
|
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
||||||
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
|
},
|
||||||
|
ancestor: "deadbeef",
|
||||||
|
expectedCommits: []*models.Commit{
|
||||||
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
|
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
||||||
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, scenario := range scenarios {
|
||||||
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
|
expectedCommits := scenario.commits
|
||||||
|
setCommitMergedStatuses(scenario.ancestor, expectedCommits)
|
||||||
|
assert.Equal(t, scenario.expectedCommits, expectedCommits)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,28 +10,30 @@ import (
|
|||||||
|
|
||||||
func TestCommitRewordCommit(t *testing.T) {
|
func TestCommitRewordCommit(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
input string
|
summary string
|
||||||
|
description string
|
||||||
}
|
}
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"Single line reword",
|
"Single line reword",
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test"}, "", nil),
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test"}, "", nil),
|
||||||
"test",
|
"test",
|
||||||
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Multi line reword",
|
"Multi line reword",
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test", "-m", "line 2\nline 3"}, "", nil),
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test", "-m", "line 2\nline 3"}, "", nil),
|
||||||
"test\nline 2\nline 3",
|
"test",
|
||||||
|
"line 2\nline 3",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
||||||
|
|
||||||
assert.NoError(t, instance.RewordLastCommit(s.input))
|
assert.NoError(t, instance.RewordLastCommit(s.summary, s.description))
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,8 @@ func TestCommitResetToCommit(t *testing.T) {
|
|||||||
func TestCommitCommitCmdObj(t *testing.T) {
|
func TestCommitCommitCmdObj(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
message string
|
summary string
|
||||||
|
description string
|
||||||
configSignoff bool
|
configSignoff bool
|
||||||
configSkipHookPrefix string
|
configSkipHookPrefix string
|
||||||
expectedArgs []string
|
expectedArgs []string
|
||||||
@@ -59,35 +62,36 @@ func TestCommitCommitCmdObj(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "Commit",
|
testName: "Commit",
|
||||||
message: "test",
|
summary: "test",
|
||||||
configSignoff: false,
|
configSignoff: false,
|
||||||
configSkipHookPrefix: "",
|
configSkipHookPrefix: "",
|
||||||
expectedArgs: []string{"commit", "-m", "test"},
|
expectedArgs: []string{"commit", "-m", "test"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Commit with --no-verify flag",
|
testName: "Commit with --no-verify flag",
|
||||||
message: "WIP: test",
|
summary: "WIP: test",
|
||||||
configSignoff: false,
|
configSignoff: false,
|
||||||
configSkipHookPrefix: "WIP",
|
configSkipHookPrefix: "WIP",
|
||||||
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
|
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Commit with multiline message",
|
testName: "Commit with multiline message",
|
||||||
message: "line1\nline2",
|
summary: "line1",
|
||||||
|
description: "line2",
|
||||||
configSignoff: false,
|
configSignoff: false,
|
||||||
configSkipHookPrefix: "",
|
configSkipHookPrefix: "",
|
||||||
expectedArgs: []string{"commit", "-m", "line1", "-m", "line2"},
|
expectedArgs: []string{"commit", "-m", "line1", "-m", "line2"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Commit with signoff",
|
testName: "Commit with signoff",
|
||||||
message: "test",
|
summary: "test",
|
||||||
configSignoff: true,
|
configSignoff: true,
|
||||||
configSkipHookPrefix: "",
|
configSkipHookPrefix: "",
|
||||||
expectedArgs: []string{"commit", "--signoff", "-m", "test"},
|
expectedArgs: []string{"commit", "--signoff", "-m", "test"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Commit with signoff and no-verify",
|
testName: "Commit with signoff and no-verify",
|
||||||
message: "WIP: test",
|
summary: "WIP: test",
|
||||||
configSignoff: true,
|
configSignoff: true,
|
||||||
configSkipHookPrefix: "WIP",
|
configSkipHookPrefix: "WIP",
|
||||||
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
|
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
|
||||||
@@ -95,7 +99,6 @@ func TestCommitCommitCmdObj(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
userConfig := config.GetDefaultConfig()
|
userConfig := config.GetDefaultConfig()
|
||||||
userConfig.Git.Commit.SignOff = s.configSignoff
|
userConfig.Git.Commit.SignOff = s.configSignoff
|
||||||
@@ -104,7 +107,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
|
|||||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
|
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
|
||||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
||||||
|
|
||||||
assert.NoError(t, instance.CommitCmdObj(s.message).Run())
|
assert.NoError(t, instance.CommitCmdObj(s.summary, s.description).Run())
|
||||||
runner.CheckForMissingCalls()
|
runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -114,7 +117,6 @@ func TestCommitCommitEditorCmdObj(t *testing.T) {
|
|||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
configSignoff bool
|
configSignoff bool
|
||||||
configVerbose string
|
|
||||||
expected []string
|
expected []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,41 +124,19 @@ func TestCommitCommitEditorCmdObj(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testName: "Commit using editor",
|
testName: "Commit using editor",
|
||||||
configSignoff: false,
|
configSignoff: false,
|
||||||
configVerbose: "default",
|
|
||||||
expected: []string{"commit"},
|
expected: []string{"commit"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
testName: "Commit with --no-verbose flag",
|
|
||||||
configSignoff: false,
|
|
||||||
configVerbose: "never",
|
|
||||||
expected: []string{"commit", "--no-verbose"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
testName: "Commit with --verbose flag",
|
|
||||||
configSignoff: false,
|
|
||||||
configVerbose: "always",
|
|
||||||
expected: []string{"commit", "--verbose"},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
testName: "Commit with --signoff",
|
testName: "Commit with --signoff",
|
||||||
configSignoff: true,
|
configSignoff: true,
|
||||||
configVerbose: "default",
|
|
||||||
expected: []string{"commit", "--signoff"},
|
expected: []string{"commit", "--signoff"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
testName: "Commit with --signoff and --no-verbose",
|
|
||||||
configSignoff: true,
|
|
||||||
configVerbose: "never",
|
|
||||||
expected: []string{"commit", "--signoff", "--no-verbose"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
userConfig := config.GetDefaultConfig()
|
userConfig := config.GetDefaultConfig()
|
||||||
userConfig.Git.Commit.SignOff = s.configSignoff
|
userConfig.Git.Commit.SignOff = s.configSignoff
|
||||||
userConfig.Git.Commit.Verbose = s.configVerbose
|
|
||||||
|
|
||||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
||||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
||||||
@@ -170,7 +150,7 @@ func TestCommitCommitEditorCmdObj(t *testing.T) {
|
|||||||
func TestCommitCreateFixupCommit(t *testing.T) {
|
func TestCommitCreateFixupCommit(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
sha string
|
hash string
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
test func(error)
|
test func(error)
|
||||||
}
|
}
|
||||||
@@ -178,7 +158,7 @@ func TestCommitCreateFixupCommit(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "valid case",
|
testName: "valid case",
|
||||||
sha: "12345",
|
hash: "12345",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"commit", "--fixup=12345"}, "", nil),
|
ExpectGitArgs([]string{"commit", "--fixup=12345"}, "", nil),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
@@ -188,10 +168,59 @@ func TestCommitCreateFixupCommit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.CreateFixupCommit(s.sha))
|
s.test(instance.CreateFixupCommit(s.hash))
|
||||||
|
s.runner.CheckForMissingCalls()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommitCreateAmendCommit(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
originalSubject string
|
||||||
|
newSubject string
|
||||||
|
newDescription string
|
||||||
|
includeFileChanges bool
|
||||||
|
runner *oscommands.FakeCmdObjRunner
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
testName: "subject only",
|
||||||
|
originalSubject: "original subject",
|
||||||
|
newSubject: "new subject",
|
||||||
|
newDescription: "",
|
||||||
|
includeFileChanges: true,
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"commit", "-m", "amend! original subject", "-m", "new subject"}, "", nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "subject and description",
|
||||||
|
originalSubject: "original subject",
|
||||||
|
newSubject: "new subject",
|
||||||
|
newDescription: "new description",
|
||||||
|
includeFileChanges: true,
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"commit", "-m", "amend! original subject", "-m", "new subject\n\nnew description"}, "", nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "without file changes",
|
||||||
|
originalSubject: "original subject",
|
||||||
|
newSubject: "new subject",
|
||||||
|
newDescription: "",
|
||||||
|
includeFileChanges: false,
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"commit", "-m", "amend! original subject", "-m", "new subject", "--only", "--allow-empty"}, "", nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
||||||
|
err := instance.CreateAmendCommit(s.originalSubject, s.newSubject, s.newDescription, s.includeFileChanges)
|
||||||
|
assert.NoError(t, err)
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -199,54 +228,88 @@ func TestCommitCreateFixupCommit(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommitShowCmdObj(t *testing.T) {
|
func TestCommitShowCmdObj(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
filterPath string
|
filterPath string
|
||||||
contextSize int
|
contextSize int
|
||||||
ignoreWhitespace bool
|
similarityThreshold int
|
||||||
expected []string
|
ignoreWhitespace bool
|
||||||
|
extDiffCmd string
|
||||||
|
expected []string
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "Default case without filter path",
|
testName: "Default case without filter path",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
expected: []string{"show", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case with filter path",
|
testName: "Default case with filter path",
|
||||||
filterPath: "file.txt",
|
filterPath: "file.txt",
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
expected: []string{"show", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--", "file.txt"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 77,
|
contextSize: 77,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
expected: []string{"show", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff, ignoring whitespace",
|
testName: "Show diff with custom similarity threshold",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 77,
|
contextSize: 3,
|
||||||
ignoreWhitespace: true,
|
similarityThreshold: 33,
|
||||||
expected: []string{"show", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=33%"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "Show diff, ignoring whitespace",
|
||||||
|
filterPath: "",
|
||||||
|
contextSize: 77,
|
||||||
|
similarityThreshold: 50,
|
||||||
|
ignoreWhitespace: true,
|
||||||
|
extDiffCmd: "",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space", "--find-renames=50%"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "Show diff with external diff command",
|
||||||
|
filterPath: "",
|
||||||
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
|
ignoreWhitespace: false,
|
||||||
|
extDiffCmd: "difft --color=always",
|
||||||
|
expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
userConfig := config.GetDefaultConfig()
|
userConfig := config.GetDefaultConfig()
|
||||||
userConfig.Git.DiffContextSize = s.contextSize
|
userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd
|
||||||
|
appState := &config.AppState{}
|
||||||
|
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||||
|
appState.DiffContextSize = s.contextSize
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
|
|
||||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
||||||
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
|
repoPaths := RepoPaths{
|
||||||
|
worktreePath: "/path/to/worktree",
|
||||||
|
}
|
||||||
|
instance := buildCommitCommands(commonDeps{userConfig: userConfig, appState: appState, runner: runner, repoPaths: &repoPaths})
|
||||||
|
|
||||||
assert.NoError(t, instance.ShowCmdObj("1234567890", s.filterPath, s.ignoreWhitespace).Run())
|
assert.NoError(t, instance.ShowCmdObj("1234567890", s.filterPath).Run())
|
||||||
runner.CheckForMissingCalls()
|
runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -261,19 +324,17 @@ func TestGetCommitMsg(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"empty",
|
"empty",
|
||||||
` commit deadbeef`,
|
``,
|
||||||
``,
|
``,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"no line breaks (single line)",
|
"no line breaks (single line)",
|
||||||
`commit deadbeef
|
`use generics to DRY up context code`,
|
||||||
use generics to DRY up context code`,
|
|
||||||
`use generics to DRY up context code`,
|
`use generics to DRY up context code`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"with line breaks",
|
"with line breaks",
|
||||||
`commit deadbeef
|
`Merge pull request #1750 from mark2185/fix-issue-template
|
||||||
Merge pull request #1750 from mark2185/fix-issue-template
|
|
||||||
|
|
||||||
'git-rev parse' should be 'git rev-parse'`,
|
'git-rev parse' should be 'git rev-parse'`,
|
||||||
`Merge pull request #1750 from mark2185/fix-issue-template
|
`Merge pull request #1750 from mark2185/fix-issue-template
|
||||||
@@ -283,10 +344,9 @@ Merge pull request #1750 from mark2185/fix-issue-template
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildCommitCommands(commonDeps{
|
instance := buildCommitCommands(commonDeps{
|
||||||
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
|
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
|
||||||
})
|
})
|
||||||
|
|
||||||
output, err := instance.GetCommitMessage("deadbeef")
|
output, err := instance.GetCommitMessage("deadbeef")
|
||||||
@@ -307,15 +367,14 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"Empty message",
|
"Empty message",
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1"}, "", nil),
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1"}, "", nil),
|
||||||
func(output string, err error) {
|
func(output string, err error) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Default case to retrieve a commit in history",
|
"Default case to retrieve a commit in history",
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "sha3 \n", nil).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1", "sha3"}, `commit sha3
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "hash3 \n", nil).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1", "hash3"}, `use generics to DRY up context code`, nil),
|
||||||
use generics to DRY up context code`, nil),
|
|
||||||
func(output string, err error) {
|
func(output string, err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "use generics to DRY up context code", output)
|
assert.Equal(t, "use generics to DRY up context code", output)
|
||||||
@@ -324,7 +383,6 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
instance := buildCommitCommands(commonDeps{runner: s.runner})
|
||||||
|
|
||||||
@@ -334,3 +392,70 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddCoAuthorToMessage(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
message string
|
||||||
|
expectedResult string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// This never happens, I think it isn't possible to create a commit
|
||||||
|
// with an empty message. Just including it for completeness.
|
||||||
|
name: "Empty message",
|
||||||
|
message: "",
|
||||||
|
expectedResult: "\n\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Just a subject, no body",
|
||||||
|
message: "Subject",
|
||||||
|
expectedResult: "Subject\n\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Subject and body",
|
||||||
|
message: "Subject\n\nBody",
|
||||||
|
expectedResult: "Subject\n\nBody\n\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Body already ending with a Co-authored-by line",
|
||||||
|
message: "Subject\n\nBody\n\nCo-authored-by: Jane Smith <jane@smith.com>",
|
||||||
|
expectedResult: "Subject\n\nBody\n\nCo-authored-by: Jane Smith <jane@smith.com>\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
result := AddCoAuthorToMessage(s.message, "John Doe <john@doe.com>")
|
||||||
|
assert.Equal(t, s.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddCoAuthorToDescription(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
description string
|
||||||
|
expectedResult string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty description",
|
||||||
|
description: "",
|
||||||
|
expectedResult: "Co-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Non-empty description",
|
||||||
|
description: "Body",
|
||||||
|
expectedResult: "Body\n\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Description already ending with a Co-authored-by line",
|
||||||
|
description: "Body\n\nCo-authored-by: Jane Smith <jane@smith.com>",
|
||||||
|
expectedResult: "Body\n\nCo-authored-by: Jane Smith <jane@smith.com>\nCo-authored-by: John Doe <john@doe.com>",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
result := AddCoAuthorToDescription(s.description, "John Doe <john@doe.com>")
|
||||||
|
assert.Equal(t, s.expectedResult, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
gogit "github.com/jesseduffield/go-git/v5"
|
gogit "github.com/jesseduffield/go-git/v5"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/sasha-s/go-deadlock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GitCommon struct {
|
type GitCommon struct {
|
||||||
@@ -12,11 +11,9 @@ type GitCommon struct {
|
|||||||
version *GitVersion
|
version *GitVersion
|
||||||
cmd oscommands.ICmdObjBuilder
|
cmd oscommands.ICmdObjBuilder
|
||||||
os *oscommands.OSCommand
|
os *oscommands.OSCommand
|
||||||
dotGitDir string
|
repoPaths *RepoPaths
|
||||||
repo *gogit.Repository
|
repo *gogit.Repository
|
||||||
config *ConfigCommands
|
config *ConfigCommands
|
||||||
// mutex for doing things like push/pull/fetch
|
|
||||||
syncMutex *deadlock.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGitCommon(
|
func NewGitCommon(
|
||||||
@@ -24,19 +21,17 @@ func NewGitCommon(
|
|||||||
version *GitVersion,
|
version *GitVersion,
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
osCommand *oscommands.OSCommand,
|
osCommand *oscommands.OSCommand,
|
||||||
dotGitDir string,
|
repoPaths *RepoPaths,
|
||||||
repo *gogit.Repository,
|
repo *gogit.Repository,
|
||||||
config *ConfigCommands,
|
config *ConfigCommands,
|
||||||
syncMutex *deadlock.Mutex,
|
|
||||||
) *GitCommon {
|
) *GitCommon {
|
||||||
return &GitCommon{
|
return &GitCommon{
|
||||||
Common: cmn,
|
Common: cmn,
|
||||||
version: version,
|
version: version,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
os: osCommand,
|
os: osCommand,
|
||||||
dotGitDir: dotGitDir,
|
repoPaths: repoPaths,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
config: config,
|
config: config,
|
||||||
syncMutex: syncMutex,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (self *ConfigCommands) GetPager(width int) string {
|
|||||||
"columnWidth": strconv.Itoa(width/2 - 6),
|
"columnWidth": strconv.Itoa(width/2 - 6),
|
||||||
}
|
}
|
||||||
|
|
||||||
pagerTemplate := self.UserConfig.Git.Paging.Pager
|
pagerTemplate := string(self.UserConfig.Git.Paging.Pager)
|
||||||
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
|
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,3 +107,7 @@ func (self *ConfigCommands) GetCoreCommentChar() byte {
|
|||||||
|
|
||||||
return '#'
|
return '#'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ConfigCommands) GetRebaseUpdateRefs() bool {
|
||||||
|
return self.gitConfig.GetBool("rebase.updateRefs")
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,18 +11,21 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
type commonDeps struct {
|
type commonDeps struct {
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
userConfig *config.UserConfig
|
userConfig *config.UserConfig
|
||||||
|
appState *config.AppState
|
||||||
gitVersion *GitVersion
|
gitVersion *GitVersion
|
||||||
gitConfig *git_config.FakeGitConfig
|
gitConfig *git_config.FakeGitConfig
|
||||||
getenv func(string) string
|
getenv func(string) string
|
||||||
removeFile func(string) error
|
removeFile func(string) error
|
||||||
dotGitDir string
|
|
||||||
common *common.Common
|
common *common.Common
|
||||||
cmd *oscommands.CmdObjBuilder
|
cmd *oscommands.CmdObjBuilder
|
||||||
|
fs afero.Fs
|
||||||
|
repoPaths *RepoPaths
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildGitCommon(deps commonDeps) *GitCommon {
|
func buildGitCommon(deps commonDeps) *GitCommon {
|
||||||
@@ -30,7 +33,17 @@ func buildGitCommon(deps commonDeps) *GitCommon {
|
|||||||
|
|
||||||
gitCommon.Common = deps.common
|
gitCommon.Common = deps.common
|
||||||
if gitCommon.Common == nil {
|
if gitCommon.Common == nil {
|
||||||
gitCommon.Common = utils.NewDummyCommonWithUserConfig(deps.userConfig)
|
gitCommon.Common = utils.NewDummyCommonWithUserConfigAndAppState(deps.userConfig, deps.appState)
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.fs != nil {
|
||||||
|
gitCommon.Fs = deps.fs
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.repoPaths != nil {
|
||||||
|
gitCommon.repoPaths = deps.repoPaths
|
||||||
|
} else {
|
||||||
|
gitCommon.repoPaths = MockRepoPaths(".git")
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := deps.runner
|
runner := deps.runner
|
||||||
@@ -81,11 +94,6 @@ func buildGitCommon(deps commonDeps) *GitCommon {
|
|||||||
TempDir: os.TempDir(),
|
TempDir: os.TempDir(),
|
||||||
})
|
})
|
||||||
|
|
||||||
gitCommon.dotGitDir = deps.dotGitDir
|
|
||||||
if gitCommon.dotGitDir == "" {
|
|
||||||
gitCommon.dotGitDir = ".git"
|
|
||||||
}
|
|
||||||
|
|
||||||
return gitCommon
|
return gitCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +104,7 @@ func buildRepo() *gogit.Repository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildFileLoader(gitCommon *GitCommon) *FileLoader {
|
func buildFileLoader(gitCommon *GitCommon) *FileLoader {
|
||||||
return NewFileLoader(gitCommon.Common, gitCommon.cmd, gitCommon.config)
|
return NewFileLoader(gitCommon, gitCommon.cmd, gitCommon.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSubmoduleCommands(deps commonDeps) *SubmoduleCommands {
|
func buildSubmoduleCommands(deps commonDeps) *SubmoduleCommands {
|
||||||
@@ -118,7 +126,7 @@ func buildWorkingTreeCommands(deps commonDeps) *WorkingTreeCommands {
|
|||||||
return NewWorkingTreeCommands(gitCommon, submoduleCommands, fileLoader)
|
return NewWorkingTreeCommands(gitCommon, submoduleCommands, fileLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPatchCommands(deps commonDeps) *PatchCommands {
|
func buildPatchCommands(deps commonDeps) *PatchCommands { //nolint:golint,unused
|
||||||
gitCommon := buildGitCommon(deps)
|
gitCommon := buildGitCommon(deps)
|
||||||
rebaseCommands := buildRebaseCommands(deps)
|
rebaseCommands := buildRebaseCommands(deps)
|
||||||
commitCommands := buildCommitCommands(deps)
|
commitCommands := buildCommitCommands(deps)
|
||||||
@@ -132,7 +140,7 @@ func buildPatchCommands(deps commonDeps) *PatchCommands {
|
|||||||
return NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
|
return NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildStatusCommands(deps commonDeps) *StatusCommands {
|
func buildStatusCommands(deps commonDeps) *StatusCommands { //nolint:golint,unused
|
||||||
gitCommon := buildGitCommon(deps)
|
gitCommon := buildGitCommon(deps)
|
||||||
|
|
||||||
return NewStatusCommands(gitCommon)
|
return NewStatusCommands(gitCommon)
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
)
|
||||||
|
|
||||||
type DiffCommands struct {
|
type DiffCommands struct {
|
||||||
*GitCommon
|
*GitCommon
|
||||||
@@ -13,7 +17,90 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
||||||
|
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
||||||
|
useExtDiff := extDiffCmd != ""
|
||||||
|
|
||||||
return self.cmd.New(
|
return self.cmd.New(
|
||||||
NewGitCmd("diff").Arg("--submodule", "--no-ext-diff", "--color").Arg(diffArgs...).ToArgv(),
|
NewGitCmd("diff").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
|
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
||||||
|
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
||||||
|
Arg("--submodule").
|
||||||
|
Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)).
|
||||||
|
Arg(diffArgs...).
|
||||||
|
Dir(self.repoPaths.worktreePath).
|
||||||
|
ToArgv(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DiffCommands) internalDiffCmdObj(diffArgs ...string) *GitCommandBuilder {
|
||||||
|
return NewGitCmd("diff").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
|
Arg("--no-ext-diff", "--no-color").
|
||||||
|
Arg(diffArgs...).
|
||||||
|
Dir(self.repoPaths.worktreePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DiffCommands) GetPathDiff(path string, staged bool) (string, error) {
|
||||||
|
return self.cmd.New(
|
||||||
|
self.internalDiffCmdObj().
|
||||||
|
ArgIf(staged, "--staged").
|
||||||
|
Arg(path).
|
||||||
|
ToArgv(),
|
||||||
|
).RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DiffCommands) GetAllDiff(staged bool) (string, error) {
|
||||||
|
return self.cmd.New(
|
||||||
|
self.internalDiffCmdObj().
|
||||||
|
ArgIf(staged, "--staged").
|
||||||
|
ToArgv(),
|
||||||
|
).RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiffToolCmdOptions struct {
|
||||||
|
// The path to show a diff for. Pass "." for the entire repo.
|
||||||
|
Filepath string
|
||||||
|
|
||||||
|
// The commit against which to show the diff. Leave empty to show a diff of
|
||||||
|
// the working copy.
|
||||||
|
FromCommit string
|
||||||
|
|
||||||
|
// The commit to diff against FromCommit. Leave empty to diff the working
|
||||||
|
// copy against FromCommit. Leave both FromCommit and ToCommit empty to show
|
||||||
|
// the diff of the unstaged working copy changes against the index if Staged
|
||||||
|
// is false, or the staged changes against HEAD if Staged is true.
|
||||||
|
ToCommit string
|
||||||
|
|
||||||
|
// Whether to reverse the left and right sides of the diff.
|
||||||
|
Reverse bool
|
||||||
|
|
||||||
|
// Whether the given Filepath is a directory. We'll pass --dir-diff to
|
||||||
|
// git-difftool in that case.
|
||||||
|
IsDirectory bool
|
||||||
|
|
||||||
|
// Whether to show the staged or the unstaged changes. Must be false if both
|
||||||
|
// FromCommit and ToCommit are non-empty.
|
||||||
|
Staged bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DiffCommands) OpenDiffToolCmdObj(opts DiffToolCmdOptions) oscommands.ICmdObj {
|
||||||
|
return self.cmd.New(NewGitCmd("difftool").
|
||||||
|
Arg("--no-prompt").
|
||||||
|
ArgIf(opts.IsDirectory, "--dir-diff").
|
||||||
|
ArgIf(opts.Staged, "--cached").
|
||||||
|
ArgIf(opts.FromCommit != "", opts.FromCommit).
|
||||||
|
ArgIf(opts.ToCommit != "", opts.ToCommit).
|
||||||
|
ArgIf(opts.Reverse, "-R").
|
||||||
|
Arg("--", opts.Filepath).
|
||||||
|
ToArgv())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DiffCommands) DiffIndexCmdObj(diffArgs ...string) oscommands.ICmdObj {
|
||||||
|
return self.cmd.New(
|
||||||
|
NewGitCmd("diff-index").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
|
Arg("--submodule", "--no-ext-diff", "--no-color", "--patch").
|
||||||
|
Arg(diffArgs...).ToArgv(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/config"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileCommands struct {
|
type FileCommands struct {
|
||||||
@@ -75,22 +76,25 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (
|
|||||||
return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil
|
return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetEditCmdStr(filename string) (string, bool) {
|
func (self *FileCommands) GetEditCmdStr(filenames []string) (string, bool) {
|
||||||
// Legacy support for old config; to be removed at some point
|
// Legacy support for old config; to be removed at some point
|
||||||
if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
||||||
if cmdStr, err := self.GetEditCmdStrLegacy(filename, 1); err == nil {
|
// If multiple files are selected, we'll simply edit just the first one.
|
||||||
|
// It's not worth fixing this for the legacy support.
|
||||||
|
if cmdStr, err := self.GetEditCmdStrLegacy(filenames[0], 1); err == nil {
|
||||||
return cmdStr, true
|
return cmdStr, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template, editInTerminal := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
template, suspend := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
||||||
|
quotedFilenames := lo.Map(filenames, func(filename string, _ int) string { return self.cmd.Quote(filename) })
|
||||||
|
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"filename": self.cmd.Quote(filename),
|
"filename": strings.Join(quotedFilenames, " "),
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
||||||
return cmdStr, editInTerminal
|
return cmdStr, suspend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
|
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
|
||||||
@@ -101,7 +105,7 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template, editInTerminal := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
template, suspend := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
||||||
|
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"filename": self.cmd.Quote(filename),
|
"filename": self.cmd.Quote(filename),
|
||||||
@@ -109,7 +113,7 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
||||||
return cmdStr, editInTerminal
|
return cmdStr, suspend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
||||||
@@ -131,6 +135,17 @@ func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber
|
|||||||
return cmdStr
|
return cmdStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
|
||||||
|
template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
||||||
|
|
||||||
|
templateValues := map[string]string{
|
||||||
|
"dir": self.cmd.Quote(path),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
|
||||||
|
return cmdStr, suspend
|
||||||
|
}
|
||||||
|
|
||||||
func (self *FileCommands) guessDefaultEditor() string {
|
func (self *FileCommands) guessDefaultEditor() string {
|
||||||
// Try to query a few places where editors get configured
|
// Try to query a few places where editors get configured
|
||||||
editor := self.config.GetCoreEditor()
|
editor := self.config.GetCoreEditor()
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileLoaderConfig interface {
|
type FileLoaderConfig interface {
|
||||||
@@ -14,15 +14,15 @@ type FileLoaderConfig interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FileLoader struct {
|
type FileLoader struct {
|
||||||
*common.Common
|
*GitCommon
|
||||||
cmd oscommands.ICmdObjBuilder
|
cmd oscommands.ICmdObjBuilder
|
||||||
config FileLoaderConfig
|
config FileLoaderConfig
|
||||||
getFileType func(string) string
|
getFileType func(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileLoader(cmn *common.Common, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
|
func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
|
||||||
return &FileLoader{
|
return &FileLoader{
|
||||||
Common: cmn,
|
GitCommon: gitCommon,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
getFileType: oscommands.FileType,
|
getFileType: oscommands.FileType,
|
||||||
config: config,
|
config: config,
|
||||||
@@ -58,13 +58,32 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
|||||||
Name: status.Name,
|
Name: status.Name,
|
||||||
PreviousName: status.PreviousName,
|
PreviousName: status.PreviousName,
|
||||||
DisplayString: status.StatusString,
|
DisplayString: status.StatusString,
|
||||||
Type: self.getFileType(status.Name),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
models.SetStatusFields(file, status.Change)
|
models.SetStatusFields(file, status.Change)
|
||||||
files = append(files, file)
|
files = append(files, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through the files to see if any of these files are actually worktrees
|
||||||
|
// so that we can render them correctly
|
||||||
|
worktreePaths := linkedWortkreePaths(self.Fs, self.repoPaths.RepoGitDirPath())
|
||||||
|
for _, file := range files {
|
||||||
|
for _, worktreePath := range worktreePaths {
|
||||||
|
absFilePath, err := filepath.Abs(file.Name)
|
||||||
|
if err != nil {
|
||||||
|
self.Log.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if absFilePath == worktreePath {
|
||||||
|
file.IsWorktree = true
|
||||||
|
// `git status` renders this worktree as a folder with a trailing slash but we'll represent it as a singular worktree
|
||||||
|
// If we include the slash, it will be rendered as a folder with a null file inside.
|
||||||
|
file.Name = strings.TrimSuffix(file.Name, "/")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +100,19 @@ type FileStatus struct {
|
|||||||
PreviousName string
|
PreviousName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FileLoader) gitStatus(opts GitStatusOptions) ([]FileStatus, error) {
|
func (self *FileLoader) gitStatus(opts GitStatusOptions) ([]FileStatus, error) {
|
||||||
cmdArgs := NewGitCmd("status").
|
cmdArgs := NewGitCmd("status").
|
||||||
Arg(opts.UntrackedFilesArg).
|
Arg(opts.UntrackedFilesArg).
|
||||||
Arg("--porcelain").
|
Arg("--porcelain").
|
||||||
Arg("-z").
|
Arg("-z").
|
||||||
ArgIf(opts.NoRenames, "--no-renames").
|
ArgIfElse(
|
||||||
|
opts.NoRenames,
|
||||||
|
"--no-renames",
|
||||||
|
fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold),
|
||||||
|
).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
statusLines, _, err := c.cmd.New(cmdArgs).DontLog().RunWithOutputs()
|
statusLines, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []FileStatus{}, err
|
return []FileStatus{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,28 +5,31 @@ import (
|
|||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileGetStatusFiles(t *testing.T) {
|
func TestFileGetStatusFiles(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
runner oscommands.ICmdObjRunner
|
similarityThreshold int
|
||||||
expectedFiles []*models.File
|
runner oscommands.ICmdObjRunner
|
||||||
|
expectedFiles []*models.File
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"No files found",
|
"No files found",
|
||||||
|
50,
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "", nil),
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "", nil),
|
||||||
[]*models.File{},
|
[]*models.File{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Several files found",
|
"Several files found",
|
||||||
|
50,
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"},
|
||||||
"MM file1.txt\x00A file3.txt\x00AM file2.txt\x00?? file4.txt\x00UU file5.txt",
|
"MM file1.txt\x00A file3.txt\x00AM file2.txt\x00?? file4.txt\x00UU file5.txt",
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
@@ -41,7 +44,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "MM file1.txt",
|
DisplayString: "MM file1.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "MM",
|
ShortStatus: "MM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -54,7 +56,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "A file3.txt",
|
DisplayString: "A file3.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "A ",
|
ShortStatus: "A ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -67,7 +68,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "AM file2.txt",
|
DisplayString: "AM file2.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "AM",
|
ShortStatus: "AM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -80,7 +80,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "?? file4.txt",
|
DisplayString: "?? file4.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "??",
|
ShortStatus: "??",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,15 +92,15 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: true,
|
HasMergeConflicts: true,
|
||||||
HasInlineMergeConflicts: true,
|
HasInlineMergeConflicts: true,
|
||||||
DisplayString: "UU file5.txt",
|
DisplayString: "UU file5.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "UU",
|
ShortStatus: "UU",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"File with new line char",
|
"File with new line char",
|
||||||
|
50,
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "MM a\nb.txt", nil),
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "MM a\nb.txt", nil),
|
||||||
[]*models.File{
|
[]*models.File{
|
||||||
{
|
{
|
||||||
Name: "a\nb.txt",
|
Name: "a\nb.txt",
|
||||||
@@ -113,15 +112,15 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "MM a\nb.txt",
|
DisplayString: "MM a\nb.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "MM",
|
ShortStatus: "MM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Renamed files",
|
"Renamed files",
|
||||||
|
50,
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"},
|
||||||
"R after1.txt\x00before1.txt\x00RM after2.txt\x00before2.txt",
|
"R after1.txt\x00before1.txt\x00RM after2.txt\x00before2.txt",
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
@@ -137,7 +136,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "R before1.txt -> after1.txt",
|
DisplayString: "R before1.txt -> after1.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "R ",
|
ShortStatus: "R ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,15 +149,15 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "RM before2.txt -> after2.txt",
|
DisplayString: "RM before2.txt -> after2.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "RM",
|
ShortStatus: "RM",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"File with arrow in name",
|
"File with arrow in name",
|
||||||
|
50,
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"},
|
||||||
`?? a -> b.txt`,
|
`?? a -> b.txt`,
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
@@ -174,7 +172,6 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasMergeConflicts: false,
|
HasMergeConflicts: false,
|
||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "?? a -> b.txt",
|
DisplayString: "?? a -> b.txt",
|
||||||
Type: "file",
|
|
||||||
ShortStatus: "??",
|
ShortStatus: "??",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -182,12 +179,14 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
|
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
|
||||||
|
|
||||||
|
appState := &config.AppState{}
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
|
|
||||||
loader := &FileLoader{
|
loader := &FileLoader{
|
||||||
Common: utils.NewDummyCommon(),
|
GitCommon: buildGitCommon(commonDeps{appState: appState}),
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
config: &FakeFileLoaderConfig{showUntrackedFiles: "yes"},
|
config: &FakeFileLoaderConfig{showUntrackedFiles: "yes"},
|
||||||
getFileType: func(string) string { return "file" },
|
getFileType: func(string) string { return "file" },
|
||||||
|
|||||||
@@ -177,36 +177,44 @@ func TestEditFileCmdStrLegacy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEditFileCmd(t *testing.T) {
|
func TestEditFilesCmd(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
filename string
|
filenames []string
|
||||||
osConfig config.OSConfig
|
osConfig config.OSConfig
|
||||||
expectedCmdStr string
|
expectedCmdStr string
|
||||||
expectedEditInTerminal bool
|
suspend bool
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
filename: "test",
|
filenames: []string{"test"},
|
||||||
osConfig: config.OSConfig{},
|
osConfig: config.OSConfig{},
|
||||||
expectedCmdStr: `vim -- "test"`,
|
expectedCmdStr: `vim -- "test"`,
|
||||||
expectedEditInTerminal: true,
|
suspend: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "test",
|
filenames: []string{"test"},
|
||||||
osConfig: config.OSConfig{
|
osConfig: config.OSConfig{
|
||||||
Edit: "nano {{filename}}",
|
Edit: "nano {{filename}}",
|
||||||
},
|
},
|
||||||
expectedCmdStr: `nano "test"`,
|
expectedCmdStr: `nano "test"`,
|
||||||
expectedEditInTerminal: true,
|
suspend: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "file/with space",
|
filenames: []string{"file/with space"},
|
||||||
osConfig: config.OSConfig{
|
osConfig: config.OSConfig{
|
||||||
EditPreset: "sublime",
|
EditPreset: "sublime",
|
||||||
},
|
},
|
||||||
expectedCmdStr: `subl -- "file/with space"`,
|
expectedCmdStr: `subl -- "file/with space"`,
|
||||||
expectedEditInTerminal: false,
|
suspend: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filenames: []string{"multiple", "files"},
|
||||||
|
osConfig: config.OSConfig{
|
||||||
|
EditPreset: "sublime",
|
||||||
|
},
|
||||||
|
expectedCmdStr: `subl -- "multiple" "files"`,
|
||||||
|
suspend: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,28 +226,28 @@ func TestEditFileCmd(t *testing.T) {
|
|||||||
userConfig: userConfig,
|
userConfig: userConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
cmdStr, editInTerminal := instance.GetEditCmdStr(s.filename)
|
cmdStr, suspend := instance.GetEditCmdStr(s.filenames)
|
||||||
assert.Equal(t, s.expectedCmdStr, cmdStr)
|
assert.Equal(t, s.expectedCmdStr, cmdStr)
|
||||||
assert.Equal(t, s.expectedEditInTerminal, editInTerminal)
|
assert.Equal(t, s.suspend, suspend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEditFileAtLineCmd(t *testing.T) {
|
func TestEditFileAtLineCmd(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
filename string
|
filename string
|
||||||
lineNumber int
|
lineNumber int
|
||||||
osConfig config.OSConfig
|
osConfig config.OSConfig
|
||||||
expectedCmdStr string
|
expectedCmdStr string
|
||||||
expectedEditInTerminal bool
|
suspend bool
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
filename: "test",
|
filename: "test",
|
||||||
lineNumber: 42,
|
lineNumber: 42,
|
||||||
osConfig: config.OSConfig{},
|
osConfig: config.OSConfig{},
|
||||||
expectedCmdStr: `vim +42 -- "test"`,
|
expectedCmdStr: `vim +42 -- "test"`,
|
||||||
expectedEditInTerminal: true,
|
suspend: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "test",
|
filename: "test",
|
||||||
@@ -247,8 +255,8 @@ func TestEditFileAtLineCmd(t *testing.T) {
|
|||||||
osConfig: config.OSConfig{
|
osConfig: config.OSConfig{
|
||||||
EditAtLine: "nano +{{line}} {{filename}}",
|
EditAtLine: "nano +{{line}} {{filename}}",
|
||||||
},
|
},
|
||||||
expectedCmdStr: `nano +35 "test"`,
|
expectedCmdStr: `nano +35 "test"`,
|
||||||
expectedEditInTerminal: true,
|
suspend: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "file/with space",
|
filename: "file/with space",
|
||||||
@@ -256,8 +264,8 @@ func TestEditFileAtLineCmd(t *testing.T) {
|
|||||||
osConfig: config.OSConfig{
|
osConfig: config.OSConfig{
|
||||||
EditPreset: "sublime",
|
EditPreset: "sublime",
|
||||||
},
|
},
|
||||||
expectedCmdStr: `subl -- "file/with space":12`,
|
expectedCmdStr: `subl -- "file/with space":12`,
|
||||||
expectedEditInTerminal: false,
|
suspend: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,9 +277,9 @@ func TestEditFileAtLineCmd(t *testing.T) {
|
|||||||
userConfig: userConfig,
|
userConfig: userConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
cmdStr, editInTerminal := instance.GetEditAtLineCmdStr(s.filename, s.lineNumber)
|
cmdStr, suspend := instance.GetEditAtLineCmdStr(s.filename, s.lineNumber)
|
||||||
assert.Equal(t, s.expectedCmdStr, cmdStr)
|
assert.Equal(t, s.expectedCmdStr, cmdStr)
|
||||||
assert.Equal(t, s.expectedEditInTerminal, editInTerminal)
|
assert.Equal(t, s.suspend, suspend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ func TestStartCmdObj(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildFlowCommands(commonDeps{})
|
instance := buildFlowCommands(commonDeps{})
|
||||||
|
|
||||||
@@ -69,7 +68,6 @@ func TestFinishCmdObj(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildFlowCommands(commonDeps{
|
instance := buildFlowCommands(commonDeps{
|
||||||
gitConfig: git_config.NewFakeGitConfig(s.gitConfigMockResponses),
|
gitConfig: git_config.NewFakeGitConfig(s.gitConfigMockResponses),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// convenience struct for building git commands. Especially useful when
|
// convenience struct for building git commands. Especially useful when
|
||||||
// including conditional args
|
// including conditional args
|
||||||
@@ -42,9 +44,50 @@ func (self *GitCommandBuilder) Config(value string) *GitCommandBuilder {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *GitCommandBuilder) RepoPath(value string) *GitCommandBuilder {
|
func (self *GitCommandBuilder) ConfigIf(condition bool, ifTrue string) *GitCommandBuilder {
|
||||||
|
if condition {
|
||||||
|
self.Config(ifTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// the -C arg will make git do a `cd` to the directory before doing anything else
|
||||||
|
func (self *GitCommandBuilder) Dir(path string) *GitCommandBuilder {
|
||||||
// repo path comes before the command
|
// repo path comes before the command
|
||||||
self.args = append([]string{"-C", value}, self.args...)
|
self.args = append([]string{"-C", path}, self.args...)
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *GitCommandBuilder) DirIf(condition bool, path string) *GitCommandBuilder {
|
||||||
|
if condition {
|
||||||
|
return self.Dir(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, you may prefer to use the Dir method instead of this one
|
||||||
|
func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
|
||||||
|
// worktree arg comes before the command
|
||||||
|
self.args = append([]string{"--work-tree", path}, self.args...)
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, you may prefer to use the Dir method instead of this one
|
||||||
|
func (self *GitCommandBuilder) GitDir(path string) *GitCommandBuilder {
|
||||||
|
// git dir arg comes before the command
|
||||||
|
self.args = append([]string{"--git-dir", path}, self.args...)
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *GitCommandBuilder) GitDirIf(condition bool, path string) *GitCommandBuilder {
|
||||||
|
if condition {
|
||||||
|
return self.GitDir(path)
|
||||||
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func TestGitCommandBuilder(t *testing.T) {
|
|||||||
expected: []string{"git", "-c", "user.email=bar", "-c", "user.name=foo", "push"},
|
expected: []string{"git", "-c", "user.email=bar", "-c", "user.name=foo", "push"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: NewGitCmd("push").RepoPath("a/b/c").ToArgv(),
|
input: NewGitCmd("push").Dir("a/b/c").ToArgv(),
|
||||||
expected: []string{"git", "-C", "a/b/c", "push"},
|
expected: []string{"git", "-C", "a/b/c", "push"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package git_commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/sasha-s/go-deadlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MainBranches struct {
|
||||||
|
// List of main branches configured by the user. Just the bare names.
|
||||||
|
configuredMainBranches []string
|
||||||
|
// Which of these actually exist in the repository. Full ref names, and it
|
||||||
|
// could be either "refs/heads/..." or "refs/remotes/origin/..." depending
|
||||||
|
// on which one exists for a given bare name.
|
||||||
|
existingMainBranches []string
|
||||||
|
|
||||||
|
cmd oscommands.ICmdObjBuilder
|
||||||
|
mutex *deadlock.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMainBranches(
|
||||||
|
configuredMainBranches []string,
|
||||||
|
cmd oscommands.ICmdObjBuilder,
|
||||||
|
) *MainBranches {
|
||||||
|
return &MainBranches{
|
||||||
|
configuredMainBranches: configuredMainBranches,
|
||||||
|
existingMainBranches: nil,
|
||||||
|
cmd: cmd,
|
||||||
|
mutex: &deadlock.Mutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of main branches that exist in the repository. This is a list of
|
||||||
|
// full ref names.
|
||||||
|
func (self *MainBranches) Get() []string {
|
||||||
|
self.mutex.Lock()
|
||||||
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
|
if self.existingMainBranches == nil {
|
||||||
|
self.existingMainBranches = self.determineMainBranches()
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.existingMainBranches
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the merge base of the given refName with the closest main branch.
|
||||||
|
func (self *MainBranches) GetMergeBase(refName string) string {
|
||||||
|
mainBranches := self.Get()
|
||||||
|
if len(mainBranches) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// We pass all existing main branches to the merge-base call; git will
|
||||||
|
// return the base commit for the closest one.
|
||||||
|
|
||||||
|
// We ignore errors from this call, since we can't distinguish whether the
|
||||||
|
// error is because one of the main branches has been deleted since the last
|
||||||
|
// call to determineMainBranches, or because the refName has no common
|
||||||
|
// history with any of the main branches. Since the former should happen
|
||||||
|
// very rarely, users must quit and restart lazygit to fix it; the latter is
|
||||||
|
// also not very common, but can totally happen and is not an error.
|
||||||
|
|
||||||
|
output, _ := self.cmd.New(
|
||||||
|
NewGitCmd("merge-base").Arg(refName).Arg(mainBranches...).
|
||||||
|
ToArgv(),
|
||||||
|
).DontLog().RunWithOutput()
|
||||||
|
return ignoringWarnings(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *MainBranches) determineMainBranches() []string {
|
||||||
|
var existingBranches []string
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
existingBranches = make([]string, len(self.configuredMainBranches))
|
||||||
|
|
||||||
|
for i, branchName := range self.configuredMainBranches {
|
||||||
|
wg.Add(1)
|
||||||
|
go utils.Safe(func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// Try to determine upstream of local main branch
|
||||||
|
if ref, err := self.cmd.New(
|
||||||
|
NewGitCmd("rev-parse").Arg("--symbolic-full-name", branchName+"@{u}").ToArgv(),
|
||||||
|
).DontLog().RunWithOutput(); err == nil {
|
||||||
|
existingBranches[i] = strings.TrimSpace(ref)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this failed, a local branch for this main branch doesn't exist or it
|
||||||
|
// has no upstream configured. Try looking for one in the "origin" remote.
|
||||||
|
ref := "refs/remotes/origin/" + branchName
|
||||||
|
if err := self.cmd.New(
|
||||||
|
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
|
||||||
|
).DontLog().Run(); err == nil {
|
||||||
|
existingBranches[i] = ref
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this failed as well, try if we have the main branch as a local
|
||||||
|
// branch. This covers the case where somebody is using git locally
|
||||||
|
// for something, but never pushing anywhere.
|
||||||
|
ref = "refs/heads/" + branchName
|
||||||
|
if err := self.cmd.New(
|
||||||
|
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
|
||||||
|
).DontLog().Run(); err == nil {
|
||||||
|
existingBranches[i] = ref
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
existingBranches = lo.Filter(existingBranches, func(branch string, _ int) bool {
|
||||||
|
return branch != ""
|
||||||
|
})
|
||||||
|
|
||||||
|
return existingBranches
|
||||||
|
}
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
"github.com/jesseduffield/lazygit/pkg/commands/patch"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PatchCommands struct {
|
type PatchCommands struct {
|
||||||
@@ -49,8 +47,8 @@ type ApplyPatchOpts struct {
|
|||||||
Reverse bool
|
Reverse bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchCommands) ApplyCustomPatch(reverse bool) error {
|
func (self *PatchCommands) ApplyCustomPatch(reverse bool, turnAddedFilesIntoDiffAgainstEmptyFile bool) error {
|
||||||
patch := self.PatchBuilder.PatchToApply(reverse)
|
patch := self.PatchBuilder.PatchToApply(reverse, turnAddedFilesIntoDiffAgainstEmptyFile)
|
||||||
|
|
||||||
return self.ApplyPatch(patch, ApplyPatchOpts{
|
return self.ApplyPatch(patch, ApplyPatchOpts{
|
||||||
Index: true,
|
Index: true,
|
||||||
@@ -81,7 +79,7 @@ func (self *PatchCommands) applyPatchFile(filepath string, opts ApplyPatchOpts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
|
func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
|
||||||
filepath := filepath.Join(self.os.GetTempDir(), utils.GetCurrentRepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
|
filepath := filepath.Join(self.os.GetTempDir(), self.repoPaths.RepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
|
||||||
self.Log.Infof("saving temporary patch to %s", filepath)
|
self.Log.Infof("saving temporary patch to %s", filepath)
|
||||||
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
|
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -96,7 +94,7 @@ func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, com
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply each patch in reverse
|
// apply each patch in reverse
|
||||||
if err := self.ApplyCustomPatch(true); err != nil {
|
if err := self.ApplyCustomPatch(true, true); err != nil {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -125,7 +123,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply each patch forward
|
// apply each patch forward
|
||||||
if err := self.ApplyCustomPatch(false); err != nil {
|
if err := self.ApplyCustomPatch(false, false); err != nil {
|
||||||
// Don't abort the rebase here; this might cause conflicts, so give
|
// Don't abort the rebase here; this might cause conflicts, so give
|
||||||
// the user a chance to resolve them
|
// the user a chance to resolve them
|
||||||
return err
|
return err
|
||||||
@@ -159,13 +157,13 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
|||||||
baseIndex := sourceCommitIdx + 1
|
baseIndex := sourceCommitIdx + 1
|
||||||
|
|
||||||
changes := []daemon.ChangeTodoAction{
|
changes := []daemon.ChangeTodoAction{
|
||||||
{Sha: commits[sourceCommitIdx].Sha, NewAction: todo.Edit},
|
{Hash: commits[sourceCommitIdx].Hash, NewAction: todo.Edit},
|
||||||
{Sha: commits[destinationCommitIdx].Sha, NewAction: todo.Edit},
|
{Hash: commits[destinationCommitIdx].Hash, NewAction: todo.Edit},
|
||||||
}
|
}
|
||||||
self.os.LogCommand(logTodoChanges(changes), false)
|
self.os.LogCommand(logTodoChanges(changes), false)
|
||||||
|
|
||||||
err := self.rebase.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
err := self.rebase.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: commits[baseIndex].Sha,
|
baseHashOrRoot: commits[baseIndex].Hash,
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||||
}).Run()
|
}).Run()
|
||||||
@@ -174,7 +172,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply each patch in reverse
|
// apply each patch in reverse
|
||||||
if err := self.ApplyCustomPatch(true); err != nil {
|
if err := self.ApplyCustomPatch(true, true); err != nil {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -221,7 +219,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
|||||||
|
|
||||||
func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, stash bool) error {
|
func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, stash bool) error {
|
||||||
if stash {
|
if stash {
|
||||||
if err := self.stash.Push(self.Tr.StashPrefix + commits[commitIdx].Sha); err != nil {
|
if err := self.stash.Push(self.Tr.StashPrefix + commits[commitIdx].Hash); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +228,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.ApplyCustomPatch(true); err != nil {
|
if err := self.ApplyCustomPatch(true, true); err != nil {
|
||||||
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
if self.status.WorkingTreeState() == enums.REBASE_MODE_REBASING {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
}
|
}
|
||||||
@@ -274,12 +272,17 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
|||||||
return self.rebase.ContinueRebase()
|
return self.rebase.ContinueRebase()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, commitIdx int) error {
|
func (self *PatchCommands) PullPatchIntoNewCommit(
|
||||||
|
commits []*models.Commit,
|
||||||
|
commitIdx int,
|
||||||
|
commitSummary string,
|
||||||
|
commitDescription string,
|
||||||
|
) error {
|
||||||
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, false); err != nil {
|
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := self.ApplyCustomPatch(true); err != nil {
|
if err := self.ApplyCustomPatch(true, true); err != nil {
|
||||||
_ = self.rebase.AbortRebase()
|
_ = self.rebase.AbortRebase()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -300,9 +303,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
head_message, _ := self.commit.GetHeadCommitMessage()
|
if err := self.commit.CommitCmdObj(commitSummary, commitDescription).Run(); err != nil {
|
||||||
new_message := fmt.Sprintf("Split from \"%s\"", head_message)
|
|
||||||
if err := self.commit.CommitCmdObj(new_message).Run(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +321,11 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
|
|||||||
// only some lines of a range of adjacent added lines. To solve this, we
|
// only some lines of a range of adjacent added lines. To solve this, we
|
||||||
// get the diff of HEAD and the original commit and then apply that.
|
// get the diff of HEAD and the original commit and then apply that.
|
||||||
func (self *PatchCommands) diffHeadAgainstCommit(commit *models.Commit) (string, error) {
|
func (self *PatchCommands) diffHeadAgainstCommit(commit *models.Commit) (string, error) {
|
||||||
cmdArgs := NewGitCmd("diff").Arg("HEAD.." + commit.Sha).ToArgv()
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
|
Arg("--no-ext-diff").
|
||||||
|
Arg("HEAD.." + commit.Hash).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).RunWithOutput()
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
package git_commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPatchApplyPatch(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
testName string
|
|
||||||
opts ApplyPatchOpts
|
|
||||||
runner *oscommands.FakeCmdObjRunner
|
|
||||||
test func(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// expectedArgs excludes the last argument which is an indeterminate filename
|
|
||||||
expectFn := func(expectedArgs []string, errToReturn error) func(cmdObj oscommands.ICmdObj) (string, error) {
|
|
||||||
return func(cmdObj oscommands.ICmdObj) (string, error) {
|
|
||||||
args := cmdObj.Args()
|
|
||||||
|
|
||||||
assert.Equal(t, len(args), len(expectedArgs)+1, fmt.Sprintf("unexpected command: %s", cmdObj.ToString()))
|
|
||||||
|
|
||||||
filename := args[len(args)-1]
|
|
||||||
|
|
||||||
content, err := os.ReadFile(filename)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "test", string(content))
|
|
||||||
|
|
||||||
return "", errToReturn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
testName: "valid case",
|
|
||||||
opts: ApplyPatchOpts{Cached: true},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
|
||||||
ExpectFunc(expectFn([]string{"git", "apply", "--cached"}, nil)),
|
|
||||||
test: func(err error) {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
testName: "command returns error",
|
|
||||||
opts: ApplyPatchOpts{Cached: true},
|
|
||||||
runner: oscommands.NewFakeRunner(t).
|
|
||||||
ExpectFunc(expectFn([]string{"git", "apply", "--cached"}, errors.New("error"))),
|
|
||||||
test: func(err error) {
|
|
||||||
assert.Error(t, err)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
|
||||||
instance := buildPatchCommands(commonDeps{runner: s.runner})
|
|
||||||
s.test(instance.ApplyPatch("test", s.opts))
|
|
||||||
s.runner.CheckForMissingCalls()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,14 +5,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
"github.com/jesseduffield/lazygit/pkg/app/daemon"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RebaseCommands struct {
|
type RebaseCommands struct {
|
||||||
@@ -35,10 +34,10 @@ func NewRebaseCommands(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, message string) error {
|
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
|
||||||
if models.IsHeadCommit(commits, index) {
|
if models.IsHeadCommit(commits, index) {
|
||||||
// we've selected the top commit so no rebase is required
|
// we've selected the top commit so no rebase is required
|
||||||
return self.commit.RewordLastCommit(message)
|
return self.commit.RewordLastCommit(summary, description)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
||||||
@@ -47,7 +46,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, me
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now the selected commit should be our head so we'll amend it with the new message
|
// now the selected commit should be our head so we'll amend it with the new message
|
||||||
err = self.commit.RewordLastCommit(message)
|
err = self.commit.RewordLastCommit(summary, description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -57,115 +56,152 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, me
|
|||||||
|
|
||||||
func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index int) (oscommands.ICmdObj, error) {
|
func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index int) (oscommands.ICmdObj, error) {
|
||||||
changes := []daemon.ChangeTodoAction{{
|
changes := []daemon.ChangeTodoAction{{
|
||||||
Sha: commits[index].Sha,
|
Hash: commits[index].Hash,
|
||||||
NewAction: todo.Reword,
|
NewAction: todo.Reword,
|
||||||
}}
|
}}
|
||||||
self.os.LogCommand(logTodoChanges(changes), false)
|
self.os.LogCommand(logTodoChanges(changes), false)
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: getBaseShaOrRoot(commits, index+1),
|
baseHashOrRoot: getBaseHashOrRoot(commits, index+1),
|
||||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, start, end int) error {
|
||||||
return self.GenericAmend(commits, index, func() error {
|
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
|
||||||
return self.commit.ResetAuthor()
|
return self.commit.ResetAuthor()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, index int, value string) error {
|
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, start, end int, value string) error {
|
||||||
return self.GenericAmend(commits, index, func() error {
|
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
|
||||||
return self.commit.SetAuthor(value)
|
return self.commit.SetAuthor(value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f func() error) error {
|
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, value string) error {
|
||||||
if models.IsHeadCommit(commits, index) {
|
return self.GenericAmend(commits, start, end, func(commit *models.Commit) error {
|
||||||
|
return self.commit.AddCoAuthor(commit.Hash, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, start, end int, f func(commit *models.Commit) error) error {
|
||||||
|
if start == end && models.IsHeadCommit(commits, start) {
|
||||||
// we've selected the top commit so no rebase is required
|
// we've selected the top commit so no rebase is required
|
||||||
return f()
|
return f(commits[start])
|
||||||
}
|
}
|
||||||
|
|
||||||
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
err := self.BeginInteractiveRebaseForCommitRange(commits, start, end, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// now the selected commit should be our head so we'll amend it
|
for commitIndex := end; commitIndex >= start; commitIndex-- {
|
||||||
err = f()
|
err = f(commits[commitIndex])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := self.ContinueRebase(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.ContinueRebase()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveCommitDown(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, index+2)
|
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+2)
|
||||||
|
|
||||||
sha := commits[index].Sha
|
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
|
return commit.Hash
|
||||||
self.os.LogCommand(fmt.Sprintf("Moving TODO down: %s", utils.ShortSha(sha)), false)
|
})
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseHashOrRoot: baseHashOrRoot,
|
||||||
instruction: daemon.NewMoveTodoDownInstruction(sha),
|
instruction: daemon.NewMoveTodosDownInstruction(hashes),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveCommitUp(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, index+1)
|
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+1)
|
||||||
|
|
||||||
sha := commits[index].Sha
|
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
|
return commit.Hash
|
||||||
self.os.LogCommand(fmt.Sprintf("Moving TODO up: %s", utils.ShortSha(sha)), false)
|
})
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseHashOrRoot: baseHashOrRoot,
|
||||||
instruction: daemon.NewMoveTodoUpInstruction(sha),
|
instruction: daemon.NewMoveTodosUpInstruction(hashes),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, index int, action todo.TodoCommand) error {
|
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx int, endIdx int, action todo.TodoCommand) error {
|
||||||
baseIndex := index + 1
|
baseIndex := endIdx + 1
|
||||||
if action == todo.Squash || action == todo.Fixup {
|
if action == todo.Squash || action == todo.Fixup {
|
||||||
baseIndex++
|
baseIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
|
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
|
||||||
|
|
||||||
|
changes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) daemon.ChangeTodoAction {
|
||||||
|
return daemon.ChangeTodoAction{
|
||||||
|
Hash: commit.Hash,
|
||||||
|
NewAction: action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
changes := []daemon.ChangeTodoAction{{
|
|
||||||
Sha: commits[index].Sha,
|
|
||||||
NewAction: action,
|
|
||||||
}}
|
|
||||||
self.os.LogCommand(logTodoChanges(changes), false)
|
self.os.LogCommand(logTodoChanges(changes), false)
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseHashOrRoot: baseHashOrRoot,
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) EditRebase(branchRef string) error {
|
func (self *RebaseCommands) EditRebase(branchRef string) error {
|
||||||
self.os.LogCommand(fmt.Sprintf("Beginning interactive rebase at '%s'", branchRef), false)
|
msg := utils.ResolvePlaceholderString(
|
||||||
|
self.Tr.Log.EditRebase,
|
||||||
|
map[string]string{
|
||||||
|
"ref": branchRef,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.os.LogCommand(msg, false)
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: branchRef,
|
baseHashOrRoot: branchRef,
|
||||||
instruction: daemon.NewInsertBreakInstruction(),
|
instruction: daemon.NewInsertBreakInstruction(),
|
||||||
|
}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) EditRebaseFromBaseCommit(targetBranchName string, baseCommit string) error {
|
||||||
|
msg := utils.ResolvePlaceholderString(
|
||||||
|
self.Tr.Log.EditRebaseFromBaseCommit,
|
||||||
|
map[string]string{
|
||||||
|
"baseCommit": baseCommit,
|
||||||
|
"targetBranchName": targetBranchName,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.os.LogCommand(msg, false)
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseHashOrRoot: baseCommit,
|
||||||
|
onto: targetBranchName,
|
||||||
|
instruction: daemon.NewInsertBreakInstruction(),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
||||||
changeTodoStr := strings.Join(slices.Map(changes, func(c daemon.ChangeTodoAction) string {
|
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
|
||||||
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
|
return fmt.Sprintf("%s:%s", c.Hash, c.NewAction)
|
||||||
}), "\n")
|
}), "\n")
|
||||||
return fmt.Sprintf("Changing TODO actions: %s", changeTodoStr)
|
return fmt.Sprintf("Changing TODO actions:\n%s", changeTodoStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrepareInteractiveRebaseCommandOpts struct {
|
type PrepareInteractiveRebaseCommandOpts struct {
|
||||||
baseShaOrRoot string
|
baseHashOrRoot string
|
||||||
|
onto string
|
||||||
instruction daemon.Instruction
|
instruction daemon.Instruction
|
||||||
overrideEditor bool
|
overrideEditor bool
|
||||||
keepCommitsThatBecomeEmpty bool
|
keepCommitsThatBecomeEmpty bool
|
||||||
@@ -173,7 +209,7 @@ type PrepareInteractiveRebaseCommandOpts struct {
|
|||||||
|
|
||||||
// PrepareInteractiveRebaseCommand returns the cmd for an interactive rebase
|
// PrepareInteractiveRebaseCommand returns the cmd for an interactive rebase
|
||||||
// we tell git to run lazygit to edit the todo list, and we pass the client
|
// we tell git to run lazygit to edit the todo list, and we pass the client
|
||||||
// lazygit a todo string to write to the todo file
|
// lazygit instructions what to do with the todo file
|
||||||
func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteractiveRebaseCommandOpts) oscommands.ICmdObj {
|
func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteractiveRebaseCommandOpts) oscommands.ICmdObj {
|
||||||
ex := oscommands.GetLazygitPath()
|
ex := oscommands.GetLazygitPath()
|
||||||
|
|
||||||
@@ -181,10 +217,11 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
Arg("--interactive").
|
Arg("--interactive").
|
||||||
Arg("--autostash").
|
Arg("--autostash").
|
||||||
Arg("--keep-empty").
|
Arg("--keep-empty").
|
||||||
ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep").
|
ArgIf(opts.keepCommitsThatBecomeEmpty && self.version.IsAtLeast(2, 26, 0), "--empty=keep").
|
||||||
Arg("--no-autosquash").
|
Arg("--no-autosquash").
|
||||||
ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges").
|
ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges").
|
||||||
Arg(opts.baseShaOrRoot).
|
ArgIf(opts.onto != "", "--onto", opts.onto).
|
||||||
|
Arg(opts.baseHashOrRoot).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
debug := "FALSE"
|
debug := "FALSE"
|
||||||
@@ -201,7 +238,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
if opts.instruction != nil {
|
if opts.instruction != nil {
|
||||||
cmdObj.AddEnvVars(daemon.ToEnvVars(opts.instruction)...)
|
cmdObj.AddEnvVars(daemon.ToEnvVars(opts.instruction)...)
|
||||||
} else {
|
} else {
|
||||||
gitSequenceEditor = "true"
|
cmdObj.AddEnvVars(daemon.ToEnvVars(daemon.NewRemoveUpdateRefsForCopiedBranchInstruction())...)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdObj.AddEnvVars(
|
cmdObj.AddEnvVars(
|
||||||
@@ -218,55 +255,127 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
return cmdObj
|
return cmdObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitRebaseEditTodo runs "git rebase --edit-todo", saving the given todosFileContent to the file
|
||||||
|
func (self *RebaseCommands) GitRebaseEditTodo(todosFileContent []byte) error {
|
||||||
|
ex := oscommands.GetLazygitPath()
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("rebase").
|
||||||
|
Arg("--edit-todo").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
debug := "FALSE"
|
||||||
|
if self.Debug {
|
||||||
|
debug = "TRUE"
|
||||||
|
}
|
||||||
|
|
||||||
|
self.Log.WithField("command", cmdArgs).Debug("RunCommand")
|
||||||
|
|
||||||
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
|
|
||||||
|
cmdObj.AddEnvVars(daemon.ToEnvVars(daemon.NewWriteRebaseTodoInstruction(todosFileContent))...)
|
||||||
|
|
||||||
|
cmdObj.AddEnvVars(
|
||||||
|
"DEBUG="+debug,
|
||||||
|
"LANG=en_US.UTF-8", // Force using EN as language
|
||||||
|
"LC_ALL=en_US.UTF-8", // Force using EN as language
|
||||||
|
"GIT_EDITOR="+ex,
|
||||||
|
"GIT_SEQUENCE_EDITOR="+ex,
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmdObj.Run()
|
||||||
|
}
|
||||||
|
|
||||||
// AmendTo amends the given commit with whatever files are staged
|
// AmendTo amends the given commit with whatever files are staged
|
||||||
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
||||||
commit := commits[commitIndex]
|
commit := commits[commitIndex]
|
||||||
|
|
||||||
if err := self.commit.CreateFixupCommit(commit.Sha); err != nil {
|
if err := self.commit.CreateFixupCommit(commit.Hash); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the sha of the commit we just created
|
// Get the hash of the commit we just created
|
||||||
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
||||||
fixupSha, err := self.cmd.New(cmdArgs).RunWithOutput()
|
fixupHash, err := self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: getBaseShaOrRoot(commits, commitIndex+1),
|
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Sha, fixupSha),
|
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Hash, fixupHash),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditRebaseTodo sets the action for a given rebase commit in the git-rebase-todo file
|
func todoFromCommit(commit *models.Commit) utils.Todo {
|
||||||
func (self *RebaseCommands) EditRebaseTodo(commit *models.Commit, action todo.TodoCommand) error {
|
if commit.Action == todo.UpdateRef {
|
||||||
|
return utils.Todo{Ref: commit.Name, Action: commit.Action}
|
||||||
|
} else {
|
||||||
|
return utils.Todo{Hash: commit.Hash, Action: commit.Action}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the action for the given commits in the git-rebase-todo file
|
||||||
|
func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo.TodoCommand) error {
|
||||||
|
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
|
||||||
|
return utils.TodoChange{
|
||||||
|
Hash: commit.Hash,
|
||||||
|
OldAction: commit.Action,
|
||||||
|
NewAction: action,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return utils.EditRebaseTodo(
|
return utils.EditRebaseTodo(
|
||||||
filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo"), commit.Sha, commit.Action, action, self.config.GetCoreCommentChar())
|
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
|
commitsWithAction,
|
||||||
|
self.config.GetCoreCommentChar(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTodoDown moves a rebase todo item down by one position
|
func (self *RebaseCommands) DeleteUpdateRefTodos(commits []*models.Commit) error {
|
||||||
func (self *RebaseCommands) MoveTodoDown(commit *models.Commit) error {
|
todosToDelete := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
|
return todoFromCommit(commit)
|
||||||
return utils.MoveTodoDown(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
|
})
|
||||||
|
|
||||||
|
todosFileContent, err := utils.DeleteTodos(
|
||||||
|
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
|
||||||
|
todosToDelete,
|
||||||
|
self.config.GetCoreCommentChar(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.GitRebaseEditTodo(todosFileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveTodoDown moves a rebase todo item down by one position
|
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
||||||
func (self *RebaseCommands) MoveTodoUp(commit *models.Commit) error {
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
return utils.MoveTodoUp(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
|
return todoFromCommit(commit)
|
||||||
|
})
|
||||||
|
|
||||||
|
return utils.MoveTodosDown(fileName, todosToMove, self.config.GetCoreCommentChar())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
|
||||||
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
|
return todoFromCommit(commit)
|
||||||
|
})
|
||||||
|
|
||||||
|
return utils.MoveTodosUp(fileName, todosToMove, self.config.GetCoreCommentChar())
|
||||||
}
|
}
|
||||||
|
|
||||||
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
|
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
|
||||||
func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) error {
|
func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) error {
|
||||||
shaOrRoot := commit.Sha + "^"
|
hashOrRoot := commit.Hash + "^"
|
||||||
if commit.IsFirstCommit() {
|
if commit.IsFirstCommit() {
|
||||||
shaOrRoot = "--root"
|
hashOrRoot = "--root"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("rebase").
|
cmdArgs := NewGitCmd("rebase").
|
||||||
Arg("--interactive", "--rebase-merges", "--autostash", "--autosquash", shaOrRoot).
|
Arg("--interactive", "--rebase-merges", "--autostash", "--autosquash", hashOrRoot).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.runSkipEditorCommand(self.cmd.New(cmdArgs))
|
return self.runSkipEditorCommand(self.cmd.New(cmdArgs))
|
||||||
@@ -277,7 +386,13 @@ func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) er
|
|||||||
func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
||||||
commits []*models.Commit, commitIndex int, keepCommitsThatBecomeEmpty bool,
|
commits []*models.Commit, commitIndex int, keepCommitsThatBecomeEmpty bool,
|
||||||
) error {
|
) error {
|
||||||
if len(commits)-1 < commitIndex {
|
return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange(
|
||||||
|
commits []*models.Commit, start, end int, keepCommitsThatBecomeEmpty bool,
|
||||||
|
) error {
|
||||||
|
if len(commits)-1 < end {
|
||||||
return errors.New("index outside of range of commits")
|
return errors.New("index outside of range of commits")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,14 +403,17 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
|||||||
return errors.New(self.Tr.DisabledForGPG)
|
return errors.New(self.Tr.DisabledForGPG)
|
||||||
}
|
}
|
||||||
|
|
||||||
changes := []daemon.ChangeTodoAction{{
|
changes := make([]daemon.ChangeTodoAction, 0, end-start)
|
||||||
Sha: commits[commitIndex].Sha,
|
for commitIndex := end; commitIndex >= start; commitIndex-- {
|
||||||
NewAction: todo.Edit,
|
changes = append(changes, daemon.ChangeTodoAction{
|
||||||
}}
|
Hash: commits[commitIndex].Hash,
|
||||||
|
NewAction: todo.Edit,
|
||||||
|
})
|
||||||
|
}
|
||||||
self.os.LogCommand(logTodoChanges(changes), false)
|
self.os.LogCommand(logTodoChanges(changes), false)
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: getBaseShaOrRoot(commits, commitIndex+1),
|
baseHashOrRoot: getBaseHashOrRoot(commits, end+1),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
|
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
|
||||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||||
@@ -304,7 +422,14 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
|||||||
|
|
||||||
// RebaseBranch interactive rebases onto a branch
|
// RebaseBranch interactive rebases onto a branch
|
||||||
func (self *RebaseCommands) RebaseBranch(branchName string) error {
|
func (self *RebaseCommands) RebaseBranch(branchName string) error {
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseShaOrRoot: branchName}).Run()
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseHashOrRoot: branchName}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) RebaseBranchFromBaseCommit(targetBranchName string, baseCommit string) error {
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseHashOrRoot: baseCommit,
|
||||||
|
onto: targetBranchName,
|
||||||
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) GenericMergeOrRebaseActionCmdObj(commandType string, command string) oscommands.ICmdObj {
|
func (self *RebaseCommands) GenericMergeOrRebaseActionCmdObj(commandType string, command string) oscommands.ICmdObj {
|
||||||
@@ -361,23 +486,25 @@ func (self *RebaseCommands) runSkipEditorCommand(cmdObj oscommands.ICmdObj) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DiscardOldFileChanges discards changes to a file from an old commit
|
// DiscardOldFileChanges discards changes to a file from an old commit
|
||||||
func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, commitIndex int, fileName string) error {
|
func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, commitIndex int, filePaths []string) error {
|
||||||
if err := self.BeginInteractiveRebaseForCommit(commits, commitIndex, false); err != nil {
|
if err := self.BeginInteractiveRebaseForCommit(commits, commitIndex, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if file exists in previous commit (this command returns an error if the file doesn't exist)
|
for _, filePath := range filePaths {
|
||||||
cmdArgs := NewGitCmd("cat-file").Arg("-e", "HEAD^:"+fileName).ToArgv()
|
// check if file exists in previous commit (this command returns an error if the file doesn't exist)
|
||||||
|
cmdArgs := NewGitCmd("cat-file").Arg("-e", "HEAD^:"+filePath).ToArgv()
|
||||||
|
|
||||||
if err := self.cmd.New(cmdArgs).Run(); err != nil {
|
if err := self.cmd.New(cmdArgs).Run(); err != nil {
|
||||||
if err := self.os.Remove(fileName); err != nil {
|
if err := self.os.Remove(filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := self.workingTree.StageFile(filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := self.workingTree.CheckoutFile("HEAD^", filePath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := self.workingTree.StageFile(fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err := self.workingTree.CheckoutFile("HEAD^", fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// amend the commit
|
// amend the commit
|
||||||
@@ -390,28 +517,48 @@ func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, comm
|
|||||||
return self.ContinueRebase()
|
return self.ContinueRebase()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CherryPickCommits begins an interactive rebase with the given shas being cherry picked onto HEAD
|
// CherryPickCommits begins an interactive rebase with the given hashes being cherry picked onto HEAD
|
||||||
func (self *RebaseCommands) CherryPickCommits(commits []*models.Commit) error {
|
func (self *RebaseCommands) CherryPickCommits(commits []*models.Commit) error {
|
||||||
commitLines := lo.Map(commits, func(commit *models.Commit, _ int) string {
|
commitLines := lo.Map(commits, func(commit *models.Commit, _ int) string {
|
||||||
return fmt.Sprintf("%s %s", utils.ShortSha(commit.Sha), commit.Name)
|
return fmt.Sprintf("%s %s", utils.ShortHash(commit.Hash), commit.Name)
|
||||||
})
|
})
|
||||||
self.os.LogCommand(fmt.Sprintf("Cherry-picking commits:\n%s", strings.Join(commitLines, "\n")), false)
|
msg := utils.ResolvePlaceholderString(
|
||||||
|
self.Tr.Log.CherryPickCommits,
|
||||||
|
map[string]string{
|
||||||
|
"commitLines": strings.Join(commitLines, "\n"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.os.LogCommand(msg, false)
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: "HEAD",
|
baseHashOrRoot: "HEAD",
|
||||||
instruction: daemon.NewCherryPickCommitsInstruction(commits),
|
instruction: daemon.NewCherryPickCommitsInstruction(commits),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CherryPickCommitsDuringRebase simply prepends the given commits to the existing git-rebase-todo file
|
||||||
|
func (self *RebaseCommands) CherryPickCommitsDuringRebase(commits []*models.Commit) error {
|
||||||
|
todoLines := lo.Map(commits, func(commit *models.Commit, _ int) daemon.TodoLine {
|
||||||
|
return daemon.TodoLine{
|
||||||
|
Action: "pick",
|
||||||
|
Commit: commit,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
todo := daemon.TodoLinesToString(todoLines)
|
||||||
|
filePath := filepath.Join(self.repoPaths.worktreeGitDirPath, "rebase-merge/git-rebase-todo")
|
||||||
|
return utils.PrependStrToTodoFile(filePath, []byte(todo))
|
||||||
|
}
|
||||||
|
|
||||||
// we can't start an interactive rebase from the first commit without passing the
|
// we can't start an interactive rebase from the first commit without passing the
|
||||||
// '--root' arg
|
// '--root' arg
|
||||||
func getBaseShaOrRoot(commits []*models.Commit, index int) string {
|
func getBaseHashOrRoot(commits []*models.Commit, index int) string {
|
||||||
// We assume that the commits slice contains the initial commit of the repo.
|
// We assume that the commits slice contains the initial commit of the repo.
|
||||||
// Technically this assumption could prove false, but it's unlikely you'll
|
// Technically this assumption could prove false, but it's unlikely you'll
|
||||||
// be starting a rebase from 300 commits ago (which is the original commit limit
|
// be starting a rebase from 300 commits ago (which is the original commit limit
|
||||||
// at time of writing)
|
// at time of writing)
|
||||||
if index < len(commits) {
|
if index < len(commits) {
|
||||||
return commits[index].Sha
|
return commits[index].Hash
|
||||||
} else {
|
} else {
|
||||||
return "--root"
|
return "--root"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ func TestRebaseRebaseBranch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildRebaseCommands(commonDeps{runner: s.runner, gitVersion: s.gitVersion})
|
instance := buildRebaseCommands(commonDeps{runner: s.runner, gitVersion: s.gitVersion})
|
||||||
s.test(instance.RebaseBranch(s.arg))
|
s.test(instance.RebaseBranch(s.arg))
|
||||||
@@ -79,7 +78,7 @@ func TestRebaseRebaseBranch(t *testing.T) {
|
|||||||
// environment variables that suppress an interactive editor
|
// environment variables that suppress an interactive editor
|
||||||
func TestRebaseSkipEditorCommand(t *testing.T) {
|
func TestRebaseSkipEditorCommand(t *testing.T) {
|
||||||
cmdArgs := []string{"git", "blah"}
|
cmdArgs := []string{"git", "blah"}
|
||||||
runner := oscommands.NewFakeRunner(t).ExpectFunc(func(cmdObj oscommands.ICmdObj) (string, error) {
|
runner := oscommands.NewFakeRunner(t).ExpectFunc("matches editor env var", func(cmdObj oscommands.ICmdObj) bool {
|
||||||
assert.EqualValues(t, cmdArgs, cmdObj.Args())
|
assert.EqualValues(t, cmdArgs, cmdObj.Args())
|
||||||
envVars := cmdObj.GetEnvVars()
|
envVars := cmdObj.GetEnvVars()
|
||||||
for _, regexStr := range []string{
|
for _, regexStr := range []string{
|
||||||
@@ -89,16 +88,15 @@ func TestRebaseSkipEditorCommand(t *testing.T) {
|
|||||||
`^GIT_SEQUENCE_EDITOR=.*$`,
|
`^GIT_SEQUENCE_EDITOR=.*$`,
|
||||||
"^" + daemon.DaemonKindEnvKey + "=" + strconv.Itoa(int(daemon.DaemonKindExitImmediately)) + "$",
|
"^" + daemon.DaemonKindEnvKey + "=" + strconv.Itoa(int(daemon.DaemonKindExitImmediately)) + "$",
|
||||||
} {
|
} {
|
||||||
regexStr := regexStr
|
|
||||||
foundMatch := lo.ContainsBy(envVars, func(envVar string) bool {
|
foundMatch := lo.ContainsBy(envVars, func(envVar string) bool {
|
||||||
return regexp.MustCompile(regexStr).MatchString(envVar)
|
return regexp.MustCompile(regexStr).MatchString(envVar)
|
||||||
})
|
})
|
||||||
if !foundMatch {
|
if !foundMatch {
|
||||||
t.Errorf("expected environment variable %s to be set", regexStr)
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
return true
|
||||||
})
|
}, "", nil)
|
||||||
instance := buildRebaseCommands(commonDeps{runner: runner})
|
instance := buildRebaseCommands(commonDeps{runner: runner})
|
||||||
err := instance.runSkipEditorCommand(instance.cmd.New(cmdArgs))
|
err := instance.runSkipEditorCommand(instance.cmd.New(cmdArgs))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@@ -111,7 +109,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||||||
gitConfigMockResponses map[string]string
|
gitConfigMockResponses map[string]string
|
||||||
commits []*models.Commit
|
commits []*models.Commit
|
||||||
commitIndex int
|
commitIndex int
|
||||||
fileName string
|
fileName []string
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
test func(error)
|
test func(error)
|
||||||
}
|
}
|
||||||
@@ -122,7 +120,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||||||
gitConfigMockResponses: nil,
|
gitConfigMockResponses: nil,
|
||||||
commits: []*models.Commit{},
|
commits: []*models.Commit{},
|
||||||
commitIndex: 0,
|
commitIndex: 0,
|
||||||
fileName: "test999.txt",
|
fileName: []string{"test999.txt"},
|
||||||
runner: oscommands.NewFakeRunner(t),
|
runner: oscommands.NewFakeRunner(t),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
@@ -131,9 +129,9 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testName: "returns error when using gpg",
|
testName: "returns error when using gpg",
|
||||||
gitConfigMockResponses: map[string]string{"commit.gpgsign": "true"},
|
gitConfigMockResponses: map[string]string{"commit.gpgsign": "true"},
|
||||||
commits: []*models.Commit{{Name: "commit", Sha: "123456"}},
|
commits: []*models.Commit{{Name: "commit", Hash: "123456"}},
|
||||||
commitIndex: 0,
|
commitIndex: 0,
|
||||||
fileName: "test999.txt",
|
fileName: []string{"test999.txt"},
|
||||||
runner: oscommands.NewFakeRunner(t),
|
runner: oscommands.NewFakeRunner(t),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
@@ -143,11 +141,11 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||||||
testName: "checks out file if it already existed",
|
testName: "checks out file if it already existed",
|
||||||
gitConfigMockResponses: nil,
|
gitConfigMockResponses: nil,
|
||||||
commits: []*models.Commit{
|
commits: []*models.Commit{
|
||||||
{Name: "commit", Sha: "123456"},
|
{Name: "commit", Hash: "123456"},
|
||||||
{Name: "commit2", Sha: "abcdef"},
|
{Name: "commit2", Hash: "abcdef"},
|
||||||
},
|
},
|
||||||
commitIndex: 0,
|
commitIndex: 0,
|
||||||
fileName: "test999.txt",
|
fileName: []string{"test999.txt"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"rebase", "--interactive", "--autostash", "--keep-empty", "--no-autosquash", "--rebase-merges", "abcdef"}, "", nil).
|
ExpectGitArgs([]string{"rebase", "--interactive", "--autostash", "--keep-empty", "--no-autosquash", "--rebase-merges", "abcdef"}, "", nil).
|
||||||
ExpectGitArgs([]string{"cat-file", "-e", "HEAD^:test999.txt"}, "", nil).
|
ExpectGitArgs([]string{"cat-file", "-e", "HEAD^:test999.txt"}, "", nil).
|
||||||
@@ -163,7 +161,6 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildRebaseCommands(commonDeps{
|
instance := buildRebaseCommands(commonDeps{
|
||||||
runner: s.runner,
|
runner: s.runner,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func NewReflogCommitLoader(common *common.Common, cmd oscommands.ICmdObjBuilder)
|
|||||||
|
|
||||||
// GetReflogCommits only returns the new reflog commits since the given lastReflogCommit
|
// GetReflogCommits only returns the new reflog commits since the given lastReflogCommit
|
||||||
// if none is passed (i.e. it's value is nil) then we get all the reflog commits
|
// if none is passed (i.e. it's value is nil) then we get all the reflog commits
|
||||||
func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit, filterPath string) ([]*models.Commit, bool, error) {
|
func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit, filterPath string, filterAuthor string) ([]*models.Commit, bool, error) {
|
||||||
commits := make([]*models.Commit, 0)
|
commits := make([]*models.Commit, 0)
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
@@ -31,38 +31,24 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
|
|||||||
Arg("-g").
|
Arg("-g").
|
||||||
Arg("--abbrev=40").
|
Arg("--abbrev=40").
|
||||||
Arg("--format=%h%x00%ct%x00%gs%x00%p").
|
Arg("--format=%h%x00%ct%x00%gs%x00%p").
|
||||||
|
ArgIf(filterAuthor != "", "--author="+filterAuthor).
|
||||||
ArgIf(filterPath != "", "--follow", "--", filterPath).
|
ArgIf(filterPath != "", "--follow", "--", filterPath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs).DontLog()
|
cmdObj := self.cmd.New(cmdArgs).DontLog()
|
||||||
|
|
||||||
onlyObtainedNewReflogCommits := false
|
onlyObtainedNewReflogCommits := false
|
||||||
err := cmdObj.RunAndProcessLines(func(line string) (bool, error) {
|
err := cmdObj.RunAndProcessLines(func(line string) (bool, error) {
|
||||||
fields := strings.SplitN(line, "\x00", 4)
|
commit, ok := self.parseLine(line)
|
||||||
if len(fields) <= 3 {
|
if !ok {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unixTimestamp, _ := strconv.Atoi(fields[1])
|
|
||||||
|
|
||||||
parentHashes := fields[3]
|
|
||||||
parents := []string{}
|
|
||||||
if len(parentHashes) > 0 {
|
|
||||||
parents = strings.Split(parentHashes, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
commit := &models.Commit{
|
|
||||||
Sha: fields[0],
|
|
||||||
Name: fields[2],
|
|
||||||
UnixTimestamp: int64(unixTimestamp),
|
|
||||||
Status: models.StatusReflog,
|
|
||||||
Parents: parents,
|
|
||||||
}
|
|
||||||
|
|
||||||
// note that the unix timestamp here is the timestamp of the COMMIT, not the reflog entry itself,
|
// note that the unix timestamp here is the timestamp of the COMMIT, not the reflog entry itself,
|
||||||
// so two consecutive reflog entries may have both the same SHA and therefore same timestamp.
|
// so two consecutive reflog entries may have both the same hash and therefore same timestamp.
|
||||||
// We use the reflog message to disambiguate, and fingers crossed that we never see the same of those
|
// We use the reflog message to disambiguate, and fingers crossed that we never see the same of those
|
||||||
// twice in a row. Reason being that it would mean we'd be erroneously exiting early.
|
// twice in a row. Reason being that it would mean we'd be erroneously exiting early.
|
||||||
if lastReflogCommit != nil && commit.Sha == lastReflogCommit.Sha && commit.UnixTimestamp == lastReflogCommit.UnixTimestamp && commit.Name == lastReflogCommit.Name {
|
if lastReflogCommit != nil && self.sameReflogCommit(commit, lastReflogCommit) {
|
||||||
onlyObtainedNewReflogCommits = true
|
onlyObtainedNewReflogCommits = true
|
||||||
// after this point we already have these reflogs loaded so we'll simply return the new ones
|
// after this point we already have these reflogs loaded so we'll simply return the new ones
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -77,3 +63,30 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
|
|||||||
|
|
||||||
return commits, onlyObtainedNewReflogCommits, nil
|
return commits, onlyObtainedNewReflogCommits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ReflogCommitLoader) sameReflogCommit(a *models.Commit, b *models.Commit) bool {
|
||||||
|
return a.Hash == b.Hash && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
|
||||||
|
fields := strings.SplitN(line, "\x00", 4)
|
||||||
|
if len(fields) <= 3 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
unixTimestamp, _ := strconv.Atoi(fields[1])
|
||||||
|
|
||||||
|
parentHashes := fields[3]
|
||||||
|
parents := []string{}
|
||||||
|
if len(parentHashes) > 0 {
|
||||||
|
parents = strings.Split(parentHashes, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &models.Commit{
|
||||||
|
Hash: fields[0],
|
||||||
|
Name: fields[2],
|
||||||
|
UnixTimestamp: int64(unixTimestamp),
|
||||||
|
Status: models.StatusReflog,
|
||||||
|
Parents: parents,
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
lastReflogCommit *models.Commit
|
lastReflogCommit *models.Commit
|
||||||
filterPath string
|
filterPath string
|
||||||
|
filterAuthor string
|
||||||
expectedCommits []*models.Commit
|
expectedCommits []*models.Commit
|
||||||
expectedOnlyObtainedNew bool
|
expectedOnlyObtainedNew bool
|
||||||
expectedError error
|
expectedError error
|
||||||
@@ -49,35 +50,35 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
lastReflogCommit: nil,
|
lastReflogCommit: nil,
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from A to B",
|
Name: "checkout: moving from A to B",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
Parents: []string{"51baa8c1"},
|
Parents: []string{"51baa8c1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from B to A",
|
Name: "checkout: moving from B to A",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
Parents: []string{"51baa8c1"},
|
Parents: []string{"51baa8c1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from A to B",
|
Name: "checkout: moving from A to B",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
Parents: []string{"51baa8c1"},
|
Parents: []string{"51baa8c1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from master to A",
|
Name: "checkout: moving from master to A",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
Parents: []string{"51baa8c1"},
|
Parents: []string{"51baa8c1"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Sha: "f4ddf2f0d4be4ccc7efa",
|
Hash: "f4ddf2f0d4be4ccc7efa",
|
||||||
Name: "checkout: moving from A to master",
|
Name: "checkout: moving from A to master",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643149435,
|
UnixTimestamp: 1643149435,
|
||||||
@@ -93,7 +94,7 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p"}, reflogOutput, nil),
|
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p"}, reflogOutput, nil),
|
||||||
|
|
||||||
lastReflogCommit: &models.Commit{
|
lastReflogCommit: &models.Commit{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from B to A",
|
Name: "checkout: moving from B to A",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
@@ -101,7 +102,7 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from A to B",
|
Name: "checkout: moving from A to B",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
@@ -117,7 +118,7 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p", "--follow", "--", "path"}, reflogOutput, nil),
|
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p", "--follow", "--", "path"}, reflogOutput, nil),
|
||||||
|
|
||||||
lastReflogCommit: &models.Commit{
|
lastReflogCommit: &models.Commit{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from B to A",
|
Name: "checkout: moving from B to A",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
@@ -126,7 +127,32 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
filterPath: "path",
|
filterPath: "path",
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{
|
{
|
||||||
Sha: "c3c4b66b64c97ffeecde",
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
|
Name: "checkout: moving from A to B",
|
||||||
|
Status: models.StatusReflog,
|
||||||
|
UnixTimestamp: 1643150483,
|
||||||
|
Parents: []string{"51baa8c1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedOnlyObtainedNew: true,
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "when passing filterAuthor",
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"-c", "log.showSignature=false", "log", "-g", "--abbrev=40", "--format=%h%x00%ct%x00%gs%x00%p", "--author=John Doe <john@doe.com>"}, reflogOutput, nil),
|
||||||
|
|
||||||
|
lastReflogCommit: &models.Commit{
|
||||||
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
|
Name: "checkout: moving from B to A",
|
||||||
|
Status: models.StatusReflog,
|
||||||
|
UnixTimestamp: 1643150483,
|
||||||
|
Parents: []string{"51baa8c1"},
|
||||||
|
},
|
||||||
|
filterAuthor: "John Doe <john@doe.com>",
|
||||||
|
expectedCommits: []*models.Commit{
|
||||||
|
{
|
||||||
|
Hash: "c3c4b66b64c97ffeecde",
|
||||||
Name: "checkout: moving from A to B",
|
Name: "checkout: moving from A to B",
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
UnixTimestamp: 1643150483,
|
UnixTimestamp: 1643150483,
|
||||||
@@ -150,14 +176,13 @@ func TestGetReflogCommits(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
scenario := scenario
|
|
||||||
t.Run(scenario.testName, func(t *testing.T) {
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
builder := &ReflogCommitLoader{
|
builder := &ReflogCommitLoader{
|
||||||
Common: utils.NewDummyCommon(),
|
Common: utils.NewDummyCommon(),
|
||||||
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
|
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, onlyObtainednew, err := builder.GetReflogCommits(scenario.lastReflogCommit, scenario.filterPath)
|
commits, onlyObtainednew, err := builder.GetReflogCommits(scenario.lastReflogCommit, scenario.filterPath, scenario.filterAuthor)
|
||||||
assert.Equal(t, scenario.expectedOnlyObtainedNew, onlyObtainednew)
|
assert.Equal(t, scenario.expectedOnlyObtainedNew, onlyObtainednew)
|
||||||
assert.Equal(t, scenario.expectedError, err)
|
assert.Equal(t, scenario.expectedError, err)
|
||||||
t.Logf("actual commits: \n%s", litter.Sdump(commits))
|
t.Logf("actual commits: \n%s", litter.Sdump(commits))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
)
|
)
|
||||||
@@ -53,7 +54,15 @@ func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName strin
|
|||||||
Arg(remoteName, "--delete", branchName).
|
Arg(remoteName, "--delete", branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
|
||||||
|
cmdArgs := NewGitCmd("push").
|
||||||
|
Arg(remoteName, "--delete", tagName).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRemoteBranchExists Returns remote branch
|
// CheckRemoteBranchExists Returns remote branch
|
||||||
@@ -66,3 +75,14 @@ func (self *RemoteCommands) CheckRemoteBranchExists(branchName string) bool {
|
|||||||
|
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve what might be a aliased URL into a full URL
|
||||||
|
// SEE: `man -P 'less +/--get-url +n' git-ls-remote`
|
||||||
|
func (self *RemoteCommands) GetRemoteURL(remoteName string) (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("ls-remote").
|
||||||
|
Arg("--get-url", remoteName).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
url, err := self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
return strings.TrimSpace(url), err
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,14 +2,16 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
gogit "github.com/jesseduffield/go-git/v5"
|
gogit "github.com/jesseduffield/go-git/v5"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RemoteLoader struct {
|
type RemoteLoader struct {
|
||||||
@@ -31,29 +33,31 @@ func NewRemoteLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) {
|
func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) {
|
||||||
cmdArgs := NewGitCmd("branch").Arg("-r").ToArgv()
|
wg := sync.WaitGroup{}
|
||||||
remoteBranchesStr, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
wg.Add(1)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
var remoteBranchesByRemoteName map[string][]*models.RemoteBranch
|
||||||
}
|
var remoteBranchesErr error
|
||||||
|
go utils.Safe(func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
remoteBranchesByRemoteName, remoteBranchesErr = self.getRemoteBranchesByRemoteName()
|
||||||
|
})
|
||||||
|
|
||||||
goGitRemotes, err := self.getGoGitRemotes()
|
goGitRemotes, err := self.getGoGitRemotes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// first step is to get our remotes from go-git
|
wg.Wait()
|
||||||
remotes := slices.Map(goGitRemotes, func(goGitRemote *gogit.Remote) *models.Remote {
|
|
||||||
remoteName := goGitRemote.Config().Name
|
|
||||||
|
|
||||||
re := regexp.MustCompile(fmt.Sprintf(`(?m)^\s*%s\/([\S]+)`, regexp.QuoteMeta(remoteName)))
|
if remoteBranchesErr != nil {
|
||||||
matches := re.FindAllStringSubmatch(remoteBranchesStr, -1)
|
return nil, remoteBranchesErr
|
||||||
branches := slices.Map(matches, func(match []string) *models.RemoteBranch {
|
}
|
||||||
return &models.RemoteBranch{
|
|
||||||
Name: match[1],
|
remotes := lo.Map(goGitRemotes, func(goGitRemote *gogit.Remote, _ int) *models.Remote {
|
||||||
RemoteName: remoteName,
|
remoteName := goGitRemote.Config().Name
|
||||||
}
|
branches := remoteBranchesByRemoteName[remoteName]
|
||||||
})
|
|
||||||
|
|
||||||
return &models.Remote{
|
return &models.Remote{
|
||||||
Name: goGitRemote.Config().Name,
|
Name: goGitRemote.Config().Name,
|
||||||
@@ -76,3 +80,51 @@ func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) {
|
|||||||
|
|
||||||
return remotes, nil
|
return remotes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RemoteLoader) getRemoteBranchesByRemoteName() (map[string][]*models.RemoteBranch, error) {
|
||||||
|
remoteBranchesByRemoteName := make(map[string][]*models.RemoteBranch)
|
||||||
|
|
||||||
|
var sortOrder string
|
||||||
|
switch strings.ToLower(self.AppState.RemoteBranchSortOrder) {
|
||||||
|
case "alphabetical":
|
||||||
|
sortOrder = "refname"
|
||||||
|
case "date":
|
||||||
|
sortOrder = "-committerdate"
|
||||||
|
default:
|
||||||
|
sortOrder = "refname"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("for-each-ref").
|
||||||
|
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
|
||||||
|
Arg("--format=%(refname:short)").
|
||||||
|
Arg("refs/remotes").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
err := self.cmd.New(cmdArgs).DontLog().RunAndProcessLines(func(line string) (bool, error) {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
split := strings.SplitN(line, "/", 2)
|
||||||
|
if len(split) != 2 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
remoteName := split[0]
|
||||||
|
name := split[1]
|
||||||
|
|
||||||
|
_, ok := remoteBranchesByRemoteName[remoteName]
|
||||||
|
if !ok {
|
||||||
|
remoteBranchesByRemoteName[remoteName] = []*models.RemoteBranch{}
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteBranchesByRemoteName[remoteName] = append(remoteBranchesByRemoteName[remoteName],
|
||||||
|
&models.RemoteBranch{
|
||||||
|
Name: name,
|
||||||
|
RemoteName: remoteName,
|
||||||
|
})
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return remoteBranchesByRemoteName, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
package git_commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
ioFs "io/fs"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RepoPaths struct {
|
||||||
|
worktreePath string
|
||||||
|
worktreeGitDirPath string
|
||||||
|
repoPath string
|
||||||
|
repoGitDirPath string
|
||||||
|
repoName string
|
||||||
|
isBareRepo bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
|
||||||
|
|
||||||
|
// Path to the current worktree. If we're in the main worktree, this will
|
||||||
|
// be the same as RepoPath()
|
||||||
|
func (self *RepoPaths) WorktreePath() string {
|
||||||
|
return self.worktreePath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path of the worktree's git dir.
|
||||||
|
// If we're in the main worktree, this will be the .git dir under the RepoPath().
|
||||||
|
// If we're in a linked worktree, it will be the directory pointed at by the worktree's .git file
|
||||||
|
func (self *RepoPaths) WorktreeGitDirPath() string {
|
||||||
|
return self.worktreeGitDirPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path of the repo. If we're in a the main worktree, this will be the same as WorktreePath()
|
||||||
|
// If we're in a bare repo, it will be the parent folder of the bare repo
|
||||||
|
func (self *RepoPaths) RepoPath() string {
|
||||||
|
return self.repoPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// path of the git-dir for the repo.
|
||||||
|
// If this is a bare repo, it will be the location of the bare repo
|
||||||
|
// If this is a non-bare repo, it will be the location of the .git dir in
|
||||||
|
// the main worktree.
|
||||||
|
func (self *RepoPaths) RepoGitDirPath() string {
|
||||||
|
return self.repoGitDirPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name of the repo. Basename of the folder containing the repo.
|
||||||
|
func (self *RepoPaths) RepoName() string {
|
||||||
|
return self.repoName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RepoPaths) IsBareRepo() bool {
|
||||||
|
return self.isBareRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the repo paths for a typical repo
|
||||||
|
func MockRepoPaths(currentPath string) *RepoPaths {
|
||||||
|
return &RepoPaths{
|
||||||
|
worktreePath: currentPath,
|
||||||
|
worktreeGitDirPath: path.Join(currentPath, ".git"),
|
||||||
|
repoPath: currentPath,
|
||||||
|
repoGitDirPath: path.Join(currentPath, ".git"),
|
||||||
|
repoName: "lazygit",
|
||||||
|
isBareRepo: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRepoPaths(
|
||||||
|
cmd oscommands.ICmdObjBuilder,
|
||||||
|
version *GitVersion,
|
||||||
|
) (*RepoPaths, error) {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return GetRepoPathsForDir(cwd, cmd, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRepoPathsForDir(
|
||||||
|
dir string,
|
||||||
|
cmd oscommands.ICmdObjBuilder,
|
||||||
|
version *GitVersion,
|
||||||
|
) (*RepoPaths, error) {
|
||||||
|
gitDirOutput, err := callGitRevParseWithDir(cmd, version, dir, "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gitDirResults := strings.Split(utils.NormalizeLinefeeds(gitDirOutput), "\n")
|
||||||
|
worktreePath := gitDirResults[0]
|
||||||
|
worktreeGitDirPath := gitDirResults[1]
|
||||||
|
repoGitDirPath := gitDirResults[2]
|
||||||
|
if version.IsOlderThanVersion(&gitPathFormatVersion) {
|
||||||
|
repoGitDirPath, err = filepath.Abs(repoGitDirPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isBareRepo := gitDirResults[3] == "true"
|
||||||
|
|
||||||
|
// If we're in a submodule, --show-superproject-working-tree will return
|
||||||
|
// a value, meaning gitDirResults will be length 5. In that case
|
||||||
|
// return the worktree path as the repoPath. Otherwise we're in a
|
||||||
|
// normal repo or a worktree so return the parent of the git common
|
||||||
|
// dir (repoGitDirPath)
|
||||||
|
isSubmodule := len(gitDirResults) == 5
|
||||||
|
|
||||||
|
var repoPath string
|
||||||
|
if isSubmodule {
|
||||||
|
repoPath = worktreePath
|
||||||
|
} else {
|
||||||
|
repoPath = path.Dir(repoGitDirPath)
|
||||||
|
}
|
||||||
|
repoName := path.Base(repoPath)
|
||||||
|
|
||||||
|
return &RepoPaths{
|
||||||
|
worktreePath: worktreePath,
|
||||||
|
worktreeGitDirPath: worktreeGitDirPath,
|
||||||
|
repoPath: repoPath,
|
||||||
|
repoGitDirPath: repoGitDirPath,
|
||||||
|
repoName: repoName,
|
||||||
|
isBareRepo: isBareRepo,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func callGitRevParseWithDir(
|
||||||
|
cmd oscommands.ICmdObjBuilder,
|
||||||
|
version *GitVersion,
|
||||||
|
dir string,
|
||||||
|
gitRevArgs ...string,
|
||||||
|
) (string, error) {
|
||||||
|
gitRevParse := NewGitCmd("rev-parse").ArgIf(version.IsAtLeastVersion(&gitPathFormatVersion), "--path-format=absolute").Arg(gitRevArgs...)
|
||||||
|
if dir != "" {
|
||||||
|
gitRevParse.Dir(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
gitCmd := cmd.New(gitRevParse.ToArgv()).DontLog()
|
||||||
|
res, err := gitCmd.RunWithOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Errorf("'%s' failed: %v", gitCmd.ToString(), err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the paths of linked worktrees
|
||||||
|
func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
||||||
|
result := []string{}
|
||||||
|
// For each directory in this path we're going to cat the `gitdir` file and append its contents to our result
|
||||||
|
// That file points us to the `.git` file in the worktree.
|
||||||
|
worktreeGitDirsPath := path.Join(repoGitDirPath, "worktrees")
|
||||||
|
|
||||||
|
// ensure the directory exists
|
||||||
|
_, err := fs.Stat(worktreeGitDirsPath)
|
||||||
|
if err != nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = afero.Walk(fs, worktreeGitDirsPath, func(currPath string, info ioFs.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gitDirPath := path.Join(currPath, "gitdir")
|
||||||
|
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
|
||||||
|
if err != nil {
|
||||||
|
// ignoring error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
|
||||||
|
// removing the .git part
|
||||||
|
worktreeDir := path.Dir(trimmedGitDir)
|
||||||
|
result = append(result, worktreeDir)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package git_commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
argFn func() []string
|
||||||
|
errFn func(getRevParseArgs argFn) error
|
||||||
|
)
|
||||||
|
|
||||||
|
type Scenario struct {
|
||||||
|
Name string
|
||||||
|
BeforeFunc func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn)
|
||||||
|
Path string
|
||||||
|
Expected *RepoPaths
|
||||||
|
Err errFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRepoPaths(t *testing.T) {
|
||||||
|
scenarios := []Scenario{
|
||||||
|
{
|
||||||
|
Name: "typical case",
|
||||||
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
|
// setup for main worktree
|
||||||
|
expectedOutput := []string{
|
||||||
|
// --show-toplevel
|
||||||
|
"/path/to/repo",
|
||||||
|
// --git-dir
|
||||||
|
"/path/to/repo/.git",
|
||||||
|
// --git-common-dir
|
||||||
|
"/path/to/repo/.git",
|
||||||
|
// --is-bare-repository
|
||||||
|
"false",
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
}
|
||||||
|
runner.ExpectGitArgs(
|
||||||
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
|
strings.Join(expectedOutput, "\n"),
|
||||||
|
nil)
|
||||||
|
},
|
||||||
|
Path: "/path/to/repo",
|
||||||
|
Expected: &RepoPaths{
|
||||||
|
worktreePath: "/path/to/repo",
|
||||||
|
worktreeGitDirPath: "/path/to/repo/.git",
|
||||||
|
repoPath: "/path/to/repo",
|
||||||
|
repoGitDirPath: "/path/to/repo/.git",
|
||||||
|
repoName: "repo",
|
||||||
|
isBareRepo: false,
|
||||||
|
},
|
||||||
|
Err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "bare repo",
|
||||||
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
|
// setup for main worktree
|
||||||
|
expectedOutput := []string{
|
||||||
|
// --show-toplevel
|
||||||
|
"/path/to/repo",
|
||||||
|
// --git-dir
|
||||||
|
"/path/to/bare_repo/bare.git",
|
||||||
|
// --git-common-dir
|
||||||
|
"/path/to/bare_repo/bare.git",
|
||||||
|
// --is-bare-repository
|
||||||
|
"true",
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
}
|
||||||
|
runner.ExpectGitArgs(
|
||||||
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
|
strings.Join(expectedOutput, "\n"),
|
||||||
|
nil)
|
||||||
|
},
|
||||||
|
Path: "/path/to/repo",
|
||||||
|
Expected: &RepoPaths{
|
||||||
|
worktreePath: "/path/to/repo",
|
||||||
|
worktreeGitDirPath: "/path/to/bare_repo/bare.git",
|
||||||
|
repoPath: "/path/to/bare_repo",
|
||||||
|
repoGitDirPath: "/path/to/bare_repo/bare.git",
|
||||||
|
repoName: "bare_repo",
|
||||||
|
isBareRepo: true,
|
||||||
|
},
|
||||||
|
Err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "submodule",
|
||||||
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
|
expectedOutput := []string{
|
||||||
|
// --show-toplevel
|
||||||
|
"/path/to/repo/submodule1",
|
||||||
|
// --git-dir
|
||||||
|
"/path/to/repo/.git/modules/submodule1",
|
||||||
|
// --git-common-dir
|
||||||
|
"/path/to/repo/.git/modules/submodule1",
|
||||||
|
// --is-bare-repository
|
||||||
|
"false",
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
"/path/to/repo",
|
||||||
|
}
|
||||||
|
runner.ExpectGitArgs(
|
||||||
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
|
strings.Join(expectedOutput, "\n"),
|
||||||
|
nil)
|
||||||
|
},
|
||||||
|
Path: "/path/to/repo/submodule1",
|
||||||
|
Expected: &RepoPaths{
|
||||||
|
worktreePath: "/path/to/repo/submodule1",
|
||||||
|
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
|
repoPath: "/path/to/repo/submodule1",
|
||||||
|
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
|
repoName: "submodule1",
|
||||||
|
isBareRepo: false,
|
||||||
|
},
|
||||||
|
Err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "git rev-parse returns an error",
|
||||||
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
|
runner.ExpectGitArgs(
|
||||||
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
|
"",
|
||||||
|
errors.New("fatal: invalid gitfile format: /path/to/repo/worktree2/.git"))
|
||||||
|
},
|
||||||
|
Path: "/path/to/repo/worktree2",
|
||||||
|
Expected: nil,
|
||||||
|
Err: func(getRevParseArgs argFn) error {
|
||||||
|
args := strings.Join(getRevParseArgs(), " ")
|
||||||
|
return errors.New(
|
||||||
|
fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.Name, func(t *testing.T) {
|
||||||
|
runner := oscommands.NewFakeRunner(t)
|
||||||
|
cmd := oscommands.NewDummyCmdObjBuilder(runner)
|
||||||
|
|
||||||
|
version, err := GetGitVersion(oscommands.NewDummyOSCommand())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getRevParseArgs := func() []string {
|
||||||
|
args := []string{"rev-parse"}
|
||||||
|
if version.IsAtLeast(2, 31, 0) {
|
||||||
|
args = append(args, "--path-format=absolute")
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
// prepare the filesystem for the scenario
|
||||||
|
s.BeforeFunc(runner, getRevParseArgs)
|
||||||
|
|
||||||
|
repoPaths, err := GetRepoPathsForDir("", cmd, version)
|
||||||
|
|
||||||
|
// check the error and the paths
|
||||||
|
if s.Err != nil {
|
||||||
|
scenarioErr := s.Err(getRevParseArgs)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.EqualError(t, err, scenarioErr.Error())
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, s.Expected, repoPaths)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,34 +60,36 @@ func (self *StashCommands) Push(message string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashCommands) Store(sha string, message string) error {
|
func (self *StashCommands) Store(hash string, message string) error {
|
||||||
trimmedMessage := strings.Trim(message, " \t")
|
trimmedMessage := strings.Trim(message, " \t")
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("stash").Arg("store").
|
cmdArgs := NewGitCmd("stash").Arg("store").
|
||||||
ArgIf(trimmedMessage != "", "-m", trimmedMessage).
|
ArgIf(trimmedMessage != "", "-m", trimmedMessage).
|
||||||
Arg(sha).
|
Arg(hash).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashCommands) Sha(index int) (string, error) {
|
func (self *StashCommands) Hash(index int) (string, error) {
|
||||||
cmdArgs := NewGitCmd("rev-parse").
|
cmdArgs := NewGitCmd("rev-parse").
|
||||||
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
|
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
sha, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
|
hash, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
|
||||||
return strings.Trim(sha, "\r\n"), err
|
return strings.Trim(hash, "\r\n"), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashCommands) ShowStashEntryCmdObj(index int, ignoreWhitespace bool) oscommands.ICmdObj {
|
func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
|
||||||
cmdArgs := NewGitCmd("stash").Arg("show").
|
cmdArgs := NewGitCmd("stash").Arg("show").
|
||||||
Arg("-p").
|
Arg("-p").
|
||||||
Arg("--stat").
|
Arg("--stat").
|
||||||
Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)).
|
Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)).
|
||||||
Arg(fmt.Sprintf("--unified=%d", self.UserConfig.Git.DiffContextSize)).
|
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||||
ArgIf(ignoreWhitespace, "--ignore-all-space").
|
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||||
|
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
||||||
Arg(fmt.Sprintf("stash@{%d}", index)).
|
Arg(fmt.Sprintf("stash@{%d}", index)).
|
||||||
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).DontLog()
|
return self.cmd.New(cmdArgs).DontLog()
|
||||||
@@ -120,9 +122,22 @@ func (self *StashCommands) StashUnstagedChanges(message string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveStagedChanges stashes only the currently staged changes. This takes a few steps
|
// SaveStagedChanges stashes only the currently staged changes.
|
||||||
// shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
|
||||||
func (self *StashCommands) SaveStagedChanges(message string) error {
|
func (self *StashCommands) SaveStagedChanges(message string) error {
|
||||||
|
if self.version.IsAtLeast(2, 35, 0) {
|
||||||
|
return self.cmd.New(NewGitCmd("stash").Arg("push").Arg("--staged").Arg("-m", message).ToArgv()).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git versions older than 2.35.0 don't support the --staged flag, so we
|
||||||
|
// need to fall back to a more complex solution.
|
||||||
|
// Shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
|
||||||
|
//
|
||||||
|
// Note that this method has a few bugs:
|
||||||
|
// - it fails when there are *only* staged changes
|
||||||
|
// - it fails when staged and unstaged changes within a single file are too close together
|
||||||
|
// We don't bother fixing these, because users can simply update git when
|
||||||
|
// they are affected by these issues.
|
||||||
|
|
||||||
// wrap in 'writing', which uses a mutex
|
// wrap in 'writing', which uses a mutex
|
||||||
if err := self.cmd.New(
|
if err := self.cmd.New(
|
||||||
NewGitCmd("stash").Arg("--keep-index").ToArgv(),
|
NewGitCmd("stash").Arg("--keep-index").ToArgv(),
|
||||||
@@ -178,7 +193,7 @@ func (self *StashCommands) StashIncludeUntrackedChanges(message string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashCommands) Rename(index int, message string) error {
|
func (self *StashCommands) Rename(index int, message string) error {
|
||||||
sha, err := self.Sha(index)
|
hash, err := self.Hash(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -187,7 +202,7 @@ func (self *StashCommands) Rename(index int, message string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = self.Store(sha, message)
|
err = self.Store(hash, message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StashLoader struct {
|
type StashLoader struct {
|
||||||
@@ -32,14 +32,14 @@ func (self *StashLoader) GetStashEntries(filterPath string) []*models.StashEntry
|
|||||||
return self.getUnfilteredStashEntries()
|
return self.getUnfilteredStashEntries()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("stash").Arg("list", "--name-only").ToArgv()
|
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--name-only", "--pretty=%ct|%gs").ToArgv()
|
||||||
rawString, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
rawString, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return self.getUnfilteredStashEntries()
|
return self.getUnfilteredStashEntries()
|
||||||
}
|
}
|
||||||
stashEntries := []*models.StashEntry{}
|
stashEntries := []*models.StashEntry{}
|
||||||
var currentStashEntry *models.StashEntry
|
var currentStashEntry *models.StashEntry
|
||||||
lines := utils.SplitLines(rawString)
|
lines := utils.SplitNul(rawString)
|
||||||
isAStash := func(line string) bool { return strings.HasPrefix(line, "stash@{") }
|
isAStash := func(line string) bool { return strings.HasPrefix(line, "stash@{") }
|
||||||
re := regexp.MustCompile(`stash@\{(\d+)\}`)
|
re := regexp.MustCompile(`stash@\{(\d+)\}`)
|
||||||
|
|
||||||
@@ -66,17 +66,32 @@ outer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry {
|
func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry {
|
||||||
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%gs").ToArgv()
|
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%ct|%gs").ToArgv()
|
||||||
|
|
||||||
rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
return slices.MapWithIndex(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
|
return lo.Map(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
|
||||||
return self.stashEntryFromLine(line, index)
|
return self.stashEntryFromLine(line, index)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry {
|
func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry {
|
||||||
return &models.StashEntry{
|
model := &models.StashEntry{
|
||||||
Name: line,
|
Name: line,
|
||||||
Index: index,
|
Index: index,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tstr, msg, ok := strings.Cut(line, "|")
|
||||||
|
if !ok {
|
||||||
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := strconv.ParseInt(tstr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
model.Name = msg
|
||||||
|
model.Recency = utils.UnixToTimeAgo(t)
|
||||||
|
|
||||||
|
return model
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ func TestGetStashEntries(t *testing.T) {
|
|||||||
"No stash entries found",
|
"No stash entries found",
|
||||||
"",
|
"",
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%gs"}, "", nil),
|
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"}, "", nil),
|
||||||
[]*models.StashEntry{},
|
[]*models.StashEntry{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Several stash entries found",
|
"Several stash entries found",
|
||||||
"",
|
"",
|
||||||
oscommands.NewFakeRunner(t).
|
oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%gs"},
|
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"},
|
||||||
"WIP on add-pkg-commands-test: 55c6af2 increase parallel build\x00WIP on master: bb86a3f update github template\x00",
|
"WIP on add-pkg-commands-test: 55c6af2 increase parallel build\x00WIP on master: bb86a3f update github template\x00",
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
@@ -47,7 +47,6 @@ func TestGetStashEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
|
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func TestStashSave(t *testing.T) {
|
|||||||
func TestStashStore(t *testing.T) {
|
func TestStashStore(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
sha string
|
hash string
|
||||||
message string
|
message string
|
||||||
expected []string
|
expected []string
|
||||||
}
|
}
|
||||||
@@ -55,89 +55,105 @@ func TestStashStore(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "Non-empty message",
|
testName: "Non-empty message",
|
||||||
sha: "0123456789abcdef",
|
hash: "0123456789abcdef",
|
||||||
message: "New stash name",
|
message: "New stash name",
|
||||||
expected: []string{"stash", "store", "-m", "New stash name", "0123456789abcdef"},
|
expected: []string{"stash", "store", "-m", "New stash name", "0123456789abcdef"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Empty message",
|
testName: "Empty message",
|
||||||
sha: "0123456789abcdef",
|
hash: "0123456789abcdef",
|
||||||
message: "",
|
message: "",
|
||||||
expected: []string{"stash", "store", "0123456789abcdef"},
|
expected: []string{"stash", "store", "0123456789abcdef"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Space message",
|
testName: "Space message",
|
||||||
sha: "0123456789abcdef",
|
hash: "0123456789abcdef",
|
||||||
message: " ",
|
message: " ",
|
||||||
expected: []string{"stash", "store", "0123456789abcdef"},
|
expected: []string{"stash", "store", "0123456789abcdef"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t).
|
runner := oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs(s.expected, "", nil)
|
ExpectGitArgs(s.expected, "", nil)
|
||||||
instance := buildStashCommands(commonDeps{runner: runner})
|
instance := buildStashCommands(commonDeps{runner: runner})
|
||||||
|
|
||||||
assert.NoError(t, instance.Store(s.sha, s.message))
|
assert.NoError(t, instance.Store(s.hash, s.message))
|
||||||
runner.CheckForMissingCalls()
|
runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStashSha(t *testing.T) {
|
func TestStashHash(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t).
|
runner := oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"rev-parse", "refs/stash@{5}"}, "14d94495194651adfd5f070590df566c11d28243\n", nil)
|
ExpectGitArgs([]string{"rev-parse", "refs/stash@{5}"}, "14d94495194651adfd5f070590df566c11d28243\n", nil)
|
||||||
instance := buildStashCommands(commonDeps{runner: runner})
|
instance := buildStashCommands(commonDeps{runner: runner})
|
||||||
|
|
||||||
sha, err := instance.Sha(5)
|
hash, err := instance.Hash(5)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "14d94495194651adfd5f070590df566c11d28243", sha)
|
assert.Equal(t, "14d94495194651adfd5f070590df566c11d28243", hash)
|
||||||
runner.CheckForMissingCalls()
|
runner.CheckForMissingCalls()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStashStashEntryCmdObj(t *testing.T) {
|
func TestStashStashEntryCmdObj(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
index int
|
index int
|
||||||
contextSize int
|
contextSize int
|
||||||
ignoreWhitespace bool
|
similarityThreshold int
|
||||||
expected []string
|
ignoreWhitespace bool
|
||||||
|
expected []string
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "Default case",
|
testName: "Default case",
|
||||||
index: 5,
|
index: 5,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "stash@{5}"},
|
ignoreWhitespace: false,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=50%", "stash@{5}"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
index: 5,
|
index: 5,
|
||||||
contextSize: 77,
|
contextSize: 77,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "stash@{5}"},
|
ignoreWhitespace: false,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "--find-renames=50%", "stash@{5}"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case",
|
testName: "Show diff with custom similarity threshold",
|
||||||
index: 5,
|
index: 5,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
ignoreWhitespace: true,
|
similarityThreshold: 33,
|
||||||
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "stash@{5}"},
|
ignoreWhitespace: false,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=33%", "stash@{5}"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "Default case",
|
||||||
|
index: 5,
|
||||||
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
|
ignoreWhitespace: true,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "stash@{5}"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
userConfig := config.GetDefaultConfig()
|
userConfig := config.GetDefaultConfig()
|
||||||
userConfig.Git.DiffContextSize = s.contextSize
|
appState := &config.AppState{}
|
||||||
instance := buildStashCommands(commonDeps{userConfig: userConfig})
|
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||||
|
appState.DiffContextSize = s.contextSize
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
|
repoPaths := RepoPaths{
|
||||||
|
worktreePath: "/path/to/worktree",
|
||||||
|
}
|
||||||
|
instance := buildStashCommands(commonDeps{userConfig: userConfig, appState: appState, repoPaths: &repoPaths})
|
||||||
|
|
||||||
cmdStr := instance.ShowStashEntryCmdObj(s.index, s.ignoreWhitespace).Args()
|
cmdStr := instance.ShowStashEntryCmdObj(s.index).Args()
|
||||||
assert.Equal(t, s.expected, cmdStr)
|
assert.Equal(t, s.expected, cmdStr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -148,8 +164,8 @@ func TestStashRename(t *testing.T) {
|
|||||||
testName string
|
testName string
|
||||||
index int
|
index int
|
||||||
message string
|
message string
|
||||||
expectedShaCmd []string
|
expectedHashCmd []string
|
||||||
shaResult string
|
hashResult string
|
||||||
expectedDropCmd []string
|
expectedDropCmd []string
|
||||||
expectedStoreCmd []string
|
expectedStoreCmd []string
|
||||||
}
|
}
|
||||||
@@ -159,8 +175,8 @@ func TestStashRename(t *testing.T) {
|
|||||||
testName: "Default case",
|
testName: "Default case",
|
||||||
index: 3,
|
index: 3,
|
||||||
message: "New message",
|
message: "New message",
|
||||||
expectedShaCmd: []string{"rev-parse", "refs/stash@{3}"},
|
expectedHashCmd: []string{"rev-parse", "refs/stash@{3}"},
|
||||||
shaResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
||||||
expectedDropCmd: []string{"stash", "drop", "stash@{3}"},
|
expectedDropCmd: []string{"stash", "drop", "stash@{3}"},
|
||||||
expectedStoreCmd: []string{"stash", "store", "-m", "New message", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
expectedStoreCmd: []string{"stash", "store", "-m", "New message", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
||||||
},
|
},
|
||||||
@@ -168,18 +184,17 @@ func TestStashRename(t *testing.T) {
|
|||||||
testName: "Empty message",
|
testName: "Empty message",
|
||||||
index: 4,
|
index: 4,
|
||||||
message: "",
|
message: "",
|
||||||
expectedShaCmd: []string{"rev-parse", "refs/stash@{4}"},
|
expectedHashCmd: []string{"rev-parse", "refs/stash@{4}"},
|
||||||
shaResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
||||||
expectedDropCmd: []string{"stash", "drop", "stash@{4}"},
|
expectedDropCmd: []string{"stash", "drop", "stash@{4}"},
|
||||||
expectedStoreCmd: []string{"stash", "store", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
expectedStoreCmd: []string{"stash", "store", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t).
|
runner := oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs(s.expectedShaCmd, s.shaResult, nil).
|
ExpectGitArgs(s.expectedHashCmd, s.hashResult, nil).
|
||||||
ExpectGitArgs(s.expectedDropCmd, "", nil).
|
ExpectGitArgs(s.expectedDropCmd, "", nil).
|
||||||
ExpectGitArgs(s.expectedStoreCmd, "", nil)
|
ExpectGitArgs(s.expectedStoreCmd, "", nil)
|
||||||
instance := buildStashCommands(commonDeps{runner: runner})
|
instance := buildStashCommands(commonDeps{runner: runner})
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,19 +23,16 @@ func NewStatusCommands(
|
|||||||
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
|
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
|
||||||
// and "interactive" for interactive rebase
|
// and "interactive" for interactive rebase
|
||||||
func (self *StatusCommands) RebaseMode() (enums.RebaseMode, error) {
|
func (self *StatusCommands) RebaseMode() (enums.RebaseMode, error) {
|
||||||
exists, err := self.os.FileExists(filepath.Join(self.dotGitDir, "rebase-apply"))
|
ok, err := self.IsInNormalRebase()
|
||||||
if err != nil {
|
if err == nil && ok {
|
||||||
return enums.REBASE_MODE_NONE, err
|
|
||||||
}
|
|
||||||
if exists {
|
|
||||||
return enums.REBASE_MODE_NORMAL, nil
|
return enums.REBASE_MODE_NORMAL, nil
|
||||||
}
|
}
|
||||||
exists, err = self.os.FileExists(filepath.Join(self.dotGitDir, "rebase-merge"))
|
ok, err = self.IsInInteractiveRebase()
|
||||||
if exists {
|
if err == nil && ok {
|
||||||
return enums.REBASE_MODE_INTERACTIVE, err
|
return enums.REBASE_MODE_INTERACTIVE, err
|
||||||
} else {
|
|
||||||
return enums.REBASE_MODE_NONE, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return enums.REBASE_MODE_NONE, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) WorkingTreeState() enums.RebaseMode {
|
func (self *StatusCommands) WorkingTreeState() enums.RebaseMode {
|
||||||
@@ -51,23 +47,30 @@ func (self *StatusCommands) WorkingTreeState() enums.RebaseMode {
|
|||||||
return enums.REBASE_MODE_NONE
|
return enums.REBASE_MODE_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) IsBareRepo() (bool, error) {
|
func (self *StatusCommands) IsBareRepo() bool {
|
||||||
return IsBareRepo(self.os)
|
return self.repoPaths.isBareRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsBareRepo(osCommand *oscommands.OSCommand) (bool, error) {
|
func (self *StatusCommands) IsInNormalRebase() (bool, error) {
|
||||||
res, err := osCommand.Cmd.New(
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-apply"))
|
||||||
NewGitCmd("rev-parse").Arg("--is-bare-repository").ToArgv(),
|
}
|
||||||
).DontLog().RunWithOutput()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The command returns output with a newline, so we need to strip
|
func (self *StatusCommands) IsInInteractiveRebase() (bool, error) {
|
||||||
return strconv.ParseBool(strings.TrimSpace(res))
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsInMergeState states whether we are still mid-merge
|
// IsInMergeState states whether we are still mid-merge
|
||||||
func (self *StatusCommands) IsInMergeState() (bool, error) {
|
func (self *StatusCommands) IsInMergeState() (bool, error) {
|
||||||
return self.os.FileExists(filepath.Join(self.dotGitDir, "MERGE_HEAD"))
|
return self.os.FileExists(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "MERGE_HEAD"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full ref (e.g. "refs/heads/mybranch") of the branch that is currently
|
||||||
|
// being rebased, or empty string when we're not in a rebase
|
||||||
|
func (self *StatusCommands) BranchBeingRebased() string {
|
||||||
|
for _, dir := range []string{"rebase-merge", "rebase-apply"} {
|
||||||
|
if bytesContent, err := os.ReadFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), dir, "head-name")); err == nil {
|
||||||
|
return strings.TrimSpace(string(bytesContent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,12 @@ func NewSubmoduleCommands(gitCommon *GitCommon) *SubmoduleCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SubmoduleCommands) GetConfigs() ([]*models.SubmoduleConfig, error) {
|
func (self *SubmoduleCommands) GetConfigs(parentModule *models.SubmoduleConfig) ([]*models.SubmoduleConfig, error) {
|
||||||
file, err := os.Open(".gitmodules")
|
gitModulesPath := ".gitmodules"
|
||||||
|
if parentModule != nil {
|
||||||
|
gitModulesPath = filepath.Join(parentModule.FullPath(), gitModulesPath)
|
||||||
|
}
|
||||||
|
file, err := os.Open(gitModulesPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -51,21 +55,27 @@ func (self *SubmoduleCommands) GetConfigs() ([]*models.SubmoduleConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configs := []*models.SubmoduleConfig{}
|
configs := []*models.SubmoduleConfig{}
|
||||||
|
lastConfigIdx := -1
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
|
|
||||||
if name, ok := firstMatch(line, `\[submodule "(.*)"\]`); ok {
|
if name, ok := firstMatch(line, `\[submodule "(.*)"\]`); ok {
|
||||||
configs = append(configs, &models.SubmoduleConfig{Name: name})
|
configs = append(configs, &models.SubmoduleConfig{
|
||||||
|
Name: name, ParentModule: parentModule,
|
||||||
|
})
|
||||||
|
lastConfigIdx = len(configs) - 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(configs) > 0 {
|
if lastConfigIdx != -1 {
|
||||||
lastConfig := configs[len(configs)-1]
|
|
||||||
|
|
||||||
if path, ok := firstMatch(line, `\s*path\s*=\s*(.*)\s*`); ok {
|
if path, ok := firstMatch(line, `\s*path\s*=\s*(.*)\s*`); ok {
|
||||||
lastConfig.Path = path
|
configs[lastConfigIdx].Path = path
|
||||||
|
nestedConfigs, err := self.GetConfigs(configs[lastConfigIdx])
|
||||||
|
if err == nil {
|
||||||
|
configs = append(configs, nestedConfigs...)
|
||||||
|
}
|
||||||
} else if url, ok := firstMatch(line, `\s*url\s*=\s*(.*)\s*`); ok {
|
} else if url, ok := firstMatch(line, `\s*url\s*=\s*(.*)\s*`); ok {
|
||||||
lastConfig.Url = url
|
configs[lastConfigIdx].Url = url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,12 +87,12 @@ func (self *SubmoduleCommands) Stash(submodule *models.SubmoduleConfig) error {
|
|||||||
// if the path does not exist then it hasn't yet been initialized so we'll swallow the error
|
// if the path does not exist then it hasn't yet been initialized so we'll swallow the error
|
||||||
// because the intention here is to have no dirty worktree state
|
// because the intention here is to have no dirty worktree state
|
||||||
if _, err := os.Stat(submodule.Path); os.IsNotExist(err) {
|
if _, err := os.Stat(submodule.Path); os.IsNotExist(err) {
|
||||||
self.Log.Infof("submodule path %s does not exist, returning", submodule.Path)
|
self.Log.Infof("submodule path %s does not exist, returning", submodule.FullPath())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("stash").
|
cmdArgs := NewGitCmd("stash").
|
||||||
RepoPath(submodule.Path).
|
Dir(submodule.FullPath()).
|
||||||
Arg("--include-untracked").
|
Arg("--include-untracked").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
@@ -90,8 +100,13 @@ func (self *SubmoduleCommands) Stash(submodule *models.SubmoduleConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SubmoduleCommands) Reset(submodule *models.SubmoduleConfig) error {
|
func (self *SubmoduleCommands) Reset(submodule *models.SubmoduleConfig) error {
|
||||||
|
parentDir := ""
|
||||||
|
if submodule.ParentModule != nil {
|
||||||
|
parentDir = submodule.ParentModule.FullPath()
|
||||||
|
}
|
||||||
cmdArgs := NewGitCmd("submodule").
|
cmdArgs := NewGitCmd("submodule").
|
||||||
Arg("update", "--init", "--force", "--", submodule.Path).
|
Arg("update", "--init", "--force", "--", submodule.Path).
|
||||||
|
DirIf(parentDir != "", parentDir).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
@@ -107,6 +122,20 @@ func (self *SubmoduleCommands) UpdateAll() error {
|
|||||||
func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
|
func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
|
||||||
// based on https://gist.github.com/myusuf3/7f645819ded92bda6677
|
// based on https://gist.github.com/myusuf3/7f645819ded92bda6677
|
||||||
|
|
||||||
|
if submodule.ParentModule != nil {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chdir(submodule.ParentModule.FullPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() { _ = os.Chdir(wd) }()
|
||||||
|
}
|
||||||
|
|
||||||
if err := self.cmd.New(
|
if err := self.cmd.New(
|
||||||
NewGitCmd("submodule").
|
NewGitCmd("submodule").
|
||||||
Arg("deinit", "--force", "--", submodule.Path).ToArgv(),
|
Arg("deinit", "--force", "--", submodule.Path).ToArgv(),
|
||||||
@@ -139,7 +168,9 @@ func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
|
|||||||
self.Log.Error(err)
|
self.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.RemoveAll(filepath.Join(self.dotGitDir, "modules", submodule.Path))
|
// We may in fact want to use the repo's git dir path but git docs say not to
|
||||||
|
// mix submodules and worktrees anyway.
|
||||||
|
return os.RemoveAll(submodule.GitDirPath(self.repoPaths.repoGitDirPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SubmoduleCommands) Add(name string, path string, url string) error {
|
func (self *SubmoduleCommands) Add(name string, path string, url string) error {
|
||||||
@@ -156,10 +187,24 @@ func (self *SubmoduleCommands) Add(name string, path string, url string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SubmoduleCommands) UpdateUrl(name string, path string, newUrl string) error {
|
func (self *SubmoduleCommands) UpdateUrl(submodule *models.SubmoduleConfig, newUrl string) error {
|
||||||
|
if submodule.ParentModule != nil {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Chdir(submodule.ParentModule.FullPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() { _ = os.Chdir(wd) }()
|
||||||
|
}
|
||||||
|
|
||||||
setUrlCmdStr := NewGitCmd("config").
|
setUrlCmdStr := NewGitCmd("config").
|
||||||
Arg(
|
Arg(
|
||||||
"--file", ".gitmodules", "submodule."+name+".url", newUrl,
|
"--file", ".gitmodules", "submodule."+submodule.Name+".url", newUrl,
|
||||||
).
|
).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
@@ -168,7 +213,7 @@ func (self *SubmoduleCommands) UpdateUrl(name string, path string, newUrl string
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
syncCmdStr := NewGitCmd("submodule").Arg("sync", "--", path).
|
syncCmdStr := NewGitCmd("submodule").Arg("sync", "--", submodule.Path).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
if err := self.cmd.New(syncCmdStr).Run(); err != nil {
|
if err := self.cmd.New(syncCmdStr).Run(); err != nil {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func NewSyncCommands(gitCommon *GitCommon) *SyncCommands {
|
|||||||
// Push pushes to a branch
|
// Push pushes to a branch
|
||||||
type PushOpts struct {
|
type PushOpts struct {
|
||||||
Force bool
|
Force bool
|
||||||
|
ForceWithLease bool
|
||||||
UpstreamRemote string
|
UpstreamRemote string
|
||||||
UpstreamBranch string
|
UpstreamBranch string
|
||||||
SetUpstream bool
|
SetUpstream bool
|
||||||
@@ -30,13 +31,14 @@ func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("push").
|
cmdArgs := NewGitCmd("push").
|
||||||
ArgIf(opts.Force, "--force-with-lease").
|
ArgIf(opts.Force, "--force").
|
||||||
|
ArgIf(opts.ForceWithLease, "--force-with-lease").
|
||||||
ArgIf(opts.SetUpstream, "--set-upstream").
|
ArgIf(opts.SetUpstream, "--set-upstream").
|
||||||
ArgIf(opts.UpstreamRemote != "", opts.UpstreamRemote).
|
ArgIf(opts.UpstreamRemote != "", opts.UpstreamRemote).
|
||||||
ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
|
ArgIf(opts.UpstreamBranch != "", "HEAD:"+opts.UpstreamBranch).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex)
|
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
|
||||||
return cmdObj, nil
|
return cmdObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +51,16 @@ func (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error {
|
|||||||
return cmdObj.Run()
|
return cmdObj.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder {
|
||||||
|
return NewGitCmd("fetch").
|
||||||
|
ArgIf(fetchAll, "--all").
|
||||||
|
// avoid writing to .git/FETCH_HEAD; this allows running a pull
|
||||||
|
// concurrently without getting errors
|
||||||
|
ArgIf(self.version.IsAtLeast(2, 29, 0), "--no-write-fetch-head")
|
||||||
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
|
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
|
||||||
cmdArgs := NewGitCmd("fetch").
|
cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()
|
||||||
ArgIf(self.UserConfig.Git.FetchAll, "--all").
|
|
||||||
ToArgv()
|
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs)
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
cmdObj.PromptOnCredentialRequest(task)
|
cmdObj.PromptOnCredentialRequest(task)
|
||||||
@@ -64,13 +72,10 @@ func (self *SyncCommands) Fetch(task gocui.Task) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
||||||
cmdArgs := NewGitCmd("fetch").
|
cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()
|
||||||
ArgIf(self.UserConfig.Git.FetchAll, "--all").
|
|
||||||
ToArgv()
|
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs)
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
cmdObj.DontLog().FailOnCredentialRequest()
|
cmdObj.DontLog().FailOnCredentialRequest()
|
||||||
cmdObj.WithMutex(self.syncMutex)
|
|
||||||
return cmdObj
|
return cmdObj
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +87,7 @@ type PullOptions struct {
|
|||||||
RemoteName string
|
RemoteName string
|
||||||
BranchName string
|
BranchName string
|
||||||
FastForwardOnly bool
|
FastForwardOnly bool
|
||||||
|
WorktreeGitDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
||||||
@@ -90,26 +96,32 @@ func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
|||||||
ArgIf(opts.FastForwardOnly, "--ff-only").
|
ArgIf(opts.FastForwardOnly, "--ff-only").
|
||||||
ArgIf(opts.RemoteName != "", opts.RemoteName).
|
ArgIf(opts.RemoteName != "", opts.RemoteName).
|
||||||
ArgIf(opts.BranchName != "", opts.BranchName).
|
ArgIf(opts.BranchName != "", opts.BranchName).
|
||||||
|
GitDirIf(opts.WorktreeGitDir != "", opts.WorktreeGitDir).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
|
// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
|
||||||
// has 'pull.rebase = interactive' configured.
|
// has 'pull.rebase = interactive' configured.
|
||||||
return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FastForward(task gocui.Task, branchName string, remoteName string, remoteBranchName string) error {
|
func (self *SyncCommands) FastForward(
|
||||||
cmdArgs := NewGitCmd("fetch").
|
task gocui.Task,
|
||||||
|
branchName string,
|
||||||
|
remoteName string,
|
||||||
|
remoteBranchName string,
|
||||||
|
) error {
|
||||||
|
cmdArgs := self.fetchCommandBuilder(false).
|
||||||
Arg(remoteName).
|
Arg(remoteName).
|
||||||
Arg(remoteBranchName + ":" + branchName).
|
Arg(remoteBranchName + ":" + branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
|
func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
|
||||||
cmdArgs := NewGitCmd("fetch").
|
cmdArgs := self.fetchCommandBuilder(false).
|
||||||
Arg(remoteName).
|
Arg(remoteName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,62 +18,70 @@ func TestSyncPush(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "Push with force disabled",
|
testName: "Push with force disabled",
|
||||||
opts: PushOpts{Force: false},
|
opts: PushOpts{ForceWithLease: false},
|
||||||
test: func(cmdObj oscommands.ICmdObj, err error) {
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
assert.Equal(t, cmdObj.Args(), []string{"git", "push"})
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testName: "Push with force-with-lease enabled",
|
||||||
|
opts: PushOpts{ForceWithLease: true},
|
||||||
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
testName: "Push with force enabled",
|
testName: "Push with force enabled",
|
||||||
opts: PushOpts{Force: true},
|
opts: PushOpts{Force: true},
|
||||||
test: func(cmdObj oscommands.ICmdObj, err error) {
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease"})
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Push with force disabled, upstream supplied",
|
testName: "Push with force disabled, upstream supplied",
|
||||||
opts: PushOpts{
|
opts: PushOpts{
|
||||||
Force: false,
|
ForceWithLease: false,
|
||||||
UpstreamRemote: "origin",
|
UpstreamRemote: "origin",
|
||||||
UpstreamBranch: "master",
|
UpstreamBranch: "master",
|
||||||
},
|
},
|
||||||
test: func(cmdObj oscommands.ICmdObj, err error) {
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "origin", "master"})
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "origin", "HEAD:master"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Push with force disabled, setting upstream",
|
testName: "Push with force disabled, setting upstream",
|
||||||
opts: PushOpts{
|
opts: PushOpts{
|
||||||
Force: false,
|
ForceWithLease: false,
|
||||||
UpstreamRemote: "origin",
|
UpstreamRemote: "origin",
|
||||||
UpstreamBranch: "master",
|
UpstreamBranch: "master",
|
||||||
SetUpstream: true,
|
SetUpstream: true,
|
||||||
},
|
},
|
||||||
test: func(cmdObj oscommands.ICmdObj, err error) {
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--set-upstream", "origin", "master"})
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--set-upstream", "origin", "HEAD:master"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Push with force enabled, setting upstream",
|
testName: "Push with force-with-lease enabled, setting upstream",
|
||||||
opts: PushOpts{
|
opts: PushOpts{
|
||||||
Force: true,
|
ForceWithLease: true,
|
||||||
UpstreamRemote: "origin",
|
UpstreamRemote: "origin",
|
||||||
UpstreamBranch: "master",
|
UpstreamBranch: "master",
|
||||||
SetUpstream: true,
|
SetUpstream: true,
|
||||||
},
|
},
|
||||||
test: func(cmdObj oscommands.ICmdObj, err error) {
|
test: func(cmdObj oscommands.ICmdObj, err error) {
|
||||||
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease", "--set-upstream", "origin", "master"})
|
assert.Equal(t, cmdObj.Args(), []string{"git", "push", "--force-with-lease", "--set-upstream", "origin", "HEAD:master"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Push with remote branch but no origin",
|
testName: "Push with remote branch but no origin",
|
||||||
opts: PushOpts{
|
opts: PushOpts{
|
||||||
Force: true,
|
ForceWithLease: true,
|
||||||
UpstreamRemote: "",
|
UpstreamRemote: "",
|
||||||
UpstreamBranch: "master",
|
UpstreamBranch: "master",
|
||||||
SetUpstream: true,
|
SetUpstream: true,
|
||||||
@@ -86,7 +94,6 @@ func TestSyncPush(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildSyncCommands(commonDeps{})
|
instance := buildSyncCommands(commonDeps{})
|
||||||
task := gocui.NewFakeTask()
|
task := gocui.NewFakeTask()
|
||||||
@@ -124,7 +131,6 @@ func TestSyncFetch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildSyncCommands(commonDeps{})
|
instance := buildSyncCommands(commonDeps{})
|
||||||
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
||||||
@@ -163,7 +169,6 @@ func TestSyncFetchBackground(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.testName, func(t *testing.T) {
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
instance := buildSyncCommands(commonDeps{})
|
instance := buildSyncCommands(commonDeps{})
|
||||||
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
instance.UserConfig.Git.FetchAll = s.fetchAllConfig
|
||||||
|
|||||||
@@ -12,16 +12,19 @@ func NewTagCommands(gitCommon *GitCommon) *TagCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagCommands) CreateLightweight(tagName string, ref string) error {
|
func (self *TagCommands) CreateLightweight(tagName string, ref string, force bool) error {
|
||||||
cmdArgs := NewGitCmd("tag").Arg("--", tagName).
|
cmdArgs := NewGitCmd("tag").
|
||||||
|
ArgIf(force, "--force").
|
||||||
|
Arg("--", tagName).
|
||||||
ArgIf(len(ref) > 0, ref).
|
ArgIf(len(ref) > 0, ref).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagCommands) CreateAnnotated(tagName, ref, msg string) error {
|
func (self *TagCommands) CreateAnnotated(tagName, ref, msg string, force bool) error {
|
||||||
cmdArgs := NewGitCmd("tag").Arg(tagName).
|
cmdArgs := NewGitCmd("tag").Arg(tagName).
|
||||||
|
ArgIf(force, "--force").
|
||||||
ArgIf(len(ref) > 0, ref).
|
ArgIf(len(ref) > 0, ref).
|
||||||
Arg("-m", msg).
|
Arg("-m", msg).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -29,7 +32,16 @@ func (self *TagCommands) CreateAnnotated(tagName, ref, msg string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TagCommands) Delete(tagName string) error {
|
func (self *TagCommands) HasTag(tagName string) bool {
|
||||||
|
cmdArgs := NewGitCmd("show-ref").
|
||||||
|
Arg("--tags", "--quiet", "--verify", "--").
|
||||||
|
Arg("refs/tags/" + tagName).
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
return self.cmd.New(cmdArgs).Run() == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *TagCommands) LocalDelete(tagName string) error {
|
||||||
cmdArgs := NewGitCmd("tag").Arg("-d", tagName).
|
cmdArgs := NewGitCmd("tag").Arg("-d", tagName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
@@ -40,5 +52,5 @@ func (self *TagCommands) Push(task gocui.Task, remoteName string, tagName string
|
|||||||
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
|
cmdArgs := NewGitCmd("push").Arg(remoteName, "tag", tagName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/common"
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TagLoader struct {
|
type TagLoader struct {
|
||||||
@@ -38,7 +38,7 @@ func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
|||||||
|
|
||||||
lineRegex := regexp.MustCompile(`^([^\s]+)(\s+)?(.*)$`)
|
lineRegex := regexp.MustCompile(`^([^\s]+)(\s+)?(.*)$`)
|
||||||
|
|
||||||
tags := slices.Map(split, func(line string) *models.Tag {
|
tags := lo.Map(split, func(line string, _ int) *models.Tag {
|
||||||
matches := lineRegex.FindStringSubmatch(line)
|
matches := lineRegex.FindStringSubmatch(line)
|
||||||
tagName := matches[1]
|
tagName := matches[1]
|
||||||
message := ""
|
message := ""
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ func TestGetTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
scenario := scenario
|
|
||||||
t.Run(scenario.testName, func(t *testing.T) {
|
t.Run(scenario.testName, func(t *testing.T) {
|
||||||
loader := &TagLoader{
|
loader := &TagLoader{
|
||||||
Common: utils.NewDummyCommon(),
|
Common: utils.NewDummyCommon(),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user