mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-10-04 21:16:48 -04:00
Compare commits
1044
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
689e708baa | ||
|
|
4e38a941de | ||
|
|
471f72e607 | ||
|
|
49f2f818c6 | ||
|
|
f5cd02b54f | ||
|
|
fd01ca3acf | ||
|
|
4845ce1e0f | ||
|
|
0cc6e39f0f | ||
|
|
e90aeb62e5 | ||
|
|
17ab91e668 | ||
|
|
964278255b | ||
|
|
56695078c3 | ||
|
|
96934d5a1d | ||
|
|
f05f81d713 | ||
|
|
9d0740427e | ||
|
|
e62aeb99ed | ||
|
|
fcf48c4f08 | ||
|
|
2ceecad381 | ||
|
|
3b85307f67 | ||
|
|
30e9bf8a75 | ||
|
|
62c6ba7d57 | ||
|
|
72b9e8328d | ||
|
|
38ab7ebefb | ||
|
|
4b30bc6dd3 | ||
|
|
626ca18a23 | ||
|
|
87c3e75811 | ||
|
|
1e05055fff | ||
|
|
0ef3832e59 | ||
|
|
b766ff9c83 | ||
|
|
b2fd6128f6 | ||
|
|
a81f9ea97c | ||
|
|
101bbb0ac5 | ||
|
|
3e11e34181 | ||
|
|
daf1fd3419 | ||
|
|
54d0ebeff0 | ||
|
|
af9699e59a | ||
|
|
d92c6d116b | ||
|
|
343a3e466a | ||
|
|
16f5348790 | ||
|
|
5979b40546 | ||
|
|
a5f78d3222 | ||
|
|
f3791e6ab6 | ||
|
|
130801dbf6 | ||
|
|
67bb7f62c5 | ||
|
|
52b1c42d38 | ||
|
|
11616190ee | ||
|
|
e5137b86cf | ||
|
|
ac3824bd7c | ||
|
|
56c9d5abeb | ||
|
|
c9196812a2 | ||
|
|
caca62b89e | ||
|
|
e15e4951ab | ||
|
|
e3944c1707 | ||
|
|
0d155e1478 | ||
|
|
2fa4ee2cac | ||
|
|
a7bfeca9c0 | ||
|
|
ab23539c0c | ||
|
|
01eece3737 | ||
|
|
57220ba478 | ||
|
|
6636d0c15a | ||
|
|
269d89ea51 | ||
|
|
dcf264b182 | ||
|
|
e37d7d5ad2 | ||
|
|
988162848a | ||
|
|
ed9519a241 | ||
|
|
7731311674 | ||
|
|
853a04dfd0 | ||
|
|
c02709698c | ||
|
|
555ab8735a | ||
|
|
20fe43f972 | ||
|
|
0fd7b9baa4 | ||
|
|
19921b7c42 | ||
|
|
c37376af74 | ||
|
|
9dbde94952 | ||
|
|
3915cb6e71 | ||
|
|
ba6cfc1f85 | ||
|
|
46ebfbbe87 | ||
|
|
3012306ac3 | ||
|
|
e987d4b519 | ||
|
|
190954568e | ||
|
|
f117eed614 | ||
|
|
a5698b86fa | ||
|
|
050a91b7d1 | ||
|
|
0b524293e1 | ||
|
|
ff4ae4a544 | ||
|
|
a0aa7a1940 | ||
|
|
6065908b0d | ||
|
|
a32be7e9fa | ||
|
|
fcf30caf40 | ||
|
|
aad2622278 | ||
|
|
2f4cedd025 | ||
|
|
e883f74f3c | ||
|
|
a1838d33e7 | ||
|
|
7e85cdd027 | ||
|
|
31e54eadaa | ||
|
|
02ca07a9be | ||
|
|
5dff9af027 | ||
|
|
437daf2f74 | ||
|
|
c0141685fe | ||
|
|
4856c96521 | ||
|
|
49f8dc2ce4 | ||
|
|
afc3061c51 | ||
|
|
2bed09ef67 | ||
|
|
0a78d0016e | ||
|
|
c0e3922d02 | ||
|
|
638c9c5fe7 | ||
|
|
e48e7a2ebc | ||
|
|
d2723ff2dd | ||
|
|
7db8fb8e9c | ||
|
|
abf914c923 | ||
|
|
698f9287d4 | ||
|
|
632695f71c | ||
|
|
ef0d319686 | ||
|
|
0397ede8a6 | ||
|
|
333802fffc | ||
|
|
3722824298 | ||
|
|
542478546d | ||
|
|
9ea2ff8f41 | ||
|
|
55236802c3 | ||
|
|
4baf008ac7 | ||
|
|
d768327814 | ||
|
|
0864affc8f | ||
|
|
40d6800fd3 | ||
|
|
20d0b4316d | ||
|
|
fe429c6184 | ||
|
|
a77dcbe3a1 | ||
|
|
2a87c048b9 | ||
|
|
c03b892270 | ||
|
|
5e26183ae1 | ||
|
|
ab7b5f6d84 | ||
|
|
4065175a58 | ||
|
|
43106b6c7f | ||
|
|
7bea41534b | ||
|
|
14a91d9829 | ||
|
|
274e24d75e | ||
|
|
a1a8cd114d | ||
|
|
c64a7904b7 | ||
|
|
3e623cd1ce | ||
|
|
6da99a49a4 | ||
|
|
977a01172f | ||
|
|
91cb1ff29a | ||
|
|
28d10c26a4 | ||
|
|
2c321011db | ||
|
|
dbd407c01d | ||
|
|
b8d5e481bb | ||
|
|
2b3525bfd6 | ||
|
|
b2c46c33b6 | ||
|
|
c44231a7d7 | ||
|
|
3518ec9f72 | ||
|
|
ec19fcf134 | ||
|
|
2d193cb296 | ||
|
|
64cd7cd9f6 | ||
|
|
eaaf123238 | ||
|
|
1c5fe8ff17 | ||
|
|
49ca7f6a84 | ||
|
|
80c212faba | ||
|
|
ae53059ed2 | ||
|
|
13829d8ff7 | ||
|
|
53b1e12110 | ||
|
|
009062534e | ||
|
|
33e81f717d | ||
|
|
ef718f3386 | ||
|
|
bf9339557e | ||
|
|
ebfc7ff7c6 | ||
|
|
928e76a82f | ||
|
|
9de8d17d84 | ||
|
|
9776be3131 | ||
|
|
7f7d9b166f | ||
|
|
3dd2e25dfa | ||
|
|
9790a7e00c | ||
|
|
a5c6a6120d | ||
|
|
bf9f9b6c04 | ||
|
|
d520d5e404 | ||
|
|
3241a9c251 | ||
|
|
4c4a2c3ff4 | ||
|
|
508cdb40a8 | ||
|
|
ae459b2377 | ||
|
|
c834e132c7 | ||
|
|
5e9ba82d7b | ||
|
|
fc78082e81 | ||
|
|
d7d5733a71 | ||
|
|
5240b2862f | ||
|
|
e1c18226bf | ||
|
|
c4e59aea66 | ||
|
|
75311750c8 | ||
|
|
16a158a025 | ||
|
|
621229bb09 | ||
|
|
536ef82866 | ||
|
|
54680e0836 | ||
|
|
fc69945a80 | ||
|
|
69a048c0ff | ||
|
|
6c6d835d50 | ||
|
|
2a72e96011 | ||
|
|
a507c836b2 | ||
|
|
8b90cca521 | ||
|
|
3573289452 | ||
|
|
87b54a4107 | ||
|
|
1b0d3829f8 | ||
|
|
aad3dc42a7 | ||
|
|
f884cc2af9 | ||
|
|
f4c8287143 | ||
|
|
03d7bc854e | ||
|
|
fdf1643f63 | ||
|
|
d93be027b6 | ||
|
|
fd5be11370 | ||
|
|
1e1fba4ce6 | ||
|
|
b174791490 | ||
|
|
a4ecd293f9 | ||
|
|
5fac40c129 | ||
|
|
ec410b2ae6 | ||
|
|
3a30211099 | ||
|
|
ec92d92bf4 | ||
|
|
87d5da511e | ||
|
|
e29ddf46d2 | ||
|
|
15288b7bf4 | ||
|
|
2828fb94fb | ||
|
|
5213a9de32 | ||
|
|
b7444b9a49 | ||
|
|
5d3b3c6656 | ||
|
|
65a28c4c3b | ||
|
|
1f2cb35cc9 | ||
|
|
2b49865d0d | ||
|
|
da47498066 | ||
|
|
2f1564d288 | ||
|
|
3610f13418 | ||
|
|
2417b70acd | ||
|
|
b61c395278 | ||
|
|
a9ef69b9c7 | ||
|
|
cf27974ea3 | ||
|
|
83356d441f | ||
|
|
49c50fc95c | ||
|
|
b719dc4d8e | ||
|
|
75121384a3 | ||
|
|
078445db63 | ||
|
|
64eb3d560b | ||
|
|
2823a7cff0 | ||
|
|
d5f2fb6003 | ||
|
|
bd0d9ef259 | ||
|
|
75d2fb1df2 | ||
|
|
13e9e1de83 | ||
|
|
93a37cf83e | ||
|
|
0f269183de | ||
|
|
4268701606 | ||
|
|
799827ee0e | ||
|
|
4a7cf6040e | ||
|
|
f455f99705 | ||
|
|
f3a5c184e1 | ||
|
|
1543b83d10 | ||
|
|
4cfeb18632 | ||
|
|
3a4422fc68 | ||
|
|
6da42b07cd | ||
|
|
954347c5bd | ||
|
|
7fb9e8fa9a | ||
|
|
5cca4c7063 | ||
|
|
53dc23a037 | ||
|
|
debfe1a21f | ||
|
|
d84986880e | ||
|
|
17bb3970c1 | ||
|
|
016d46526c | ||
|
|
0766b14afd | ||
|
|
4624d496a2 | ||
|
|
ea03ae5ee3 | ||
|
|
51e5816dd7 | ||
|
|
c1b4201726 | ||
|
|
0b0910573b | ||
|
|
92bce7de43 | ||
|
|
e98cc4d016 | ||
|
|
2ffd52acd1 | ||
|
|
24e98d1792 | ||
|
|
a50712b6c2 | ||
|
|
64cebfc0a8 | ||
|
|
b07109de4d | ||
|
|
59303981f9 | ||
|
|
62e31efd0f | ||
|
|
f6f2a52dee | ||
|
|
579053d5a3 | ||
|
|
10db72d223 | ||
|
|
c3cf48cc49 | ||
|
|
949e131ebe | ||
|
|
b62546c391 | ||
|
|
de8dc935a3 | ||
|
|
dd765801db | ||
|
|
111407d9a6 | ||
|
|
9f03f9e95d | ||
|
|
181b00b758 | ||
|
|
e1e4e1be1f | ||
|
|
fdeaf9cea0 | ||
|
|
b0a766cc95 | ||
|
|
f858460ab9 | ||
|
|
b2cbd93619 | ||
|
|
8da43af924 | ||
|
|
7edf629eeb | ||
|
|
1e8b8471ca | ||
|
|
095eb130e9 | ||
|
|
f08b3e9e1d | ||
|
|
8f3e59b78e | ||
|
|
eaf3bf0971 | ||
|
|
4883c867bb | ||
|
|
a58770ee1b | ||
|
|
7655f6864e | ||
|
|
286e5f4849 | ||
|
|
052974be65 | ||
|
|
85523402d6 | ||
|
|
f473d23d65 | ||
|
|
59a937ee7a | ||
|
|
53f8249ee1 | ||
|
|
f71274b601 | ||
|
|
f2fd435c05 | ||
|
|
4e361e1a87 | ||
|
|
696e78fcc8 | ||
|
|
b71aa5e23b | ||
|
|
72cf3efb1d | ||
|
|
ae610dcbb7 | ||
|
|
d11e11d179 | ||
|
|
825f5c0a91 | ||
|
|
26e3a93fc3 | ||
|
|
1ceb5a6b37 | ||
|
|
65b731f484 | ||
|
|
c6a7722066 | ||
|
|
1ab70ec645 | ||
|
|
e181de1180 | ||
|
|
c712b1d0fe | ||
|
|
c4e5995cb9 | ||
|
|
be3683ccc8 | ||
|
|
7e7309f97e | ||
|
|
d2b6f93858 | ||
|
|
a91fe517d3 | ||
|
|
8a328a553a | ||
|
|
3d56357294 | ||
|
|
9b2a0c4538 | ||
|
|
a04ad24a60 | ||
|
|
0d633896ae | ||
|
|
611fabde11 | ||
|
|
f8073c7188 | ||
|
|
4dadcd2ace | ||
|
|
b18f12ca0f | ||
|
|
c67979abbb | ||
|
|
0e489bb5cc | ||
|
|
647f533e71 | ||
|
|
b22149d832 | ||
|
|
396215a5c9 | ||
|
|
42c157a5e6 | ||
|
|
a793f709b6 | ||
|
|
f74551e464 | ||
|
|
e06b1cef60 | ||
|
|
2d0c7cb0fc | ||
|
|
f5b8619ded | ||
|
|
4c6c915a77 | ||
|
|
064fae41e7 | ||
|
|
d4ef8e53d5 | ||
|
|
b15a1c7ae7 | ||
|
|
6f0182f11c | ||
|
|
371998e635 | ||
|
|
072b465fa6 | ||
|
|
8302575078 | ||
|
|
8edcd71234 | ||
|
|
5446683881 | ||
|
|
b91beb68e1 | ||
|
|
5659f1f3e9 | ||
|
|
753b16b697 | ||
|
|
da7a28c117 | ||
|
|
c35743d7ad | ||
|
|
f0eafabd6d | ||
|
|
fc4cf5d196 | ||
|
|
4e880e56c4 | ||
|
|
e8e39f5ce2 | ||
|
|
370ab2d19c | ||
|
|
fa8cd47227 | ||
|
|
9ec77bba91 | ||
|
|
4ec9262ff6 | ||
|
|
ba21d4e651 | ||
|
|
3cffed9412 | ||
|
|
90b8fd242d | ||
|
|
1191aca60f | ||
|
|
2f01af49e8 | ||
|
|
32fef9aadb | ||
|
|
717cb40f05 | ||
|
|
ef7d1a8602 | ||
|
|
a6656e307c | ||
|
|
442592a149 | ||
|
|
ac335907ae | ||
|
|
b07ce19b9a | ||
|
|
079c5a9905 | ||
|
|
a2c4fad410 | ||
|
|
567e898e22 | ||
|
|
14a29d6d6f | ||
|
|
8e2ed8c538 | ||
|
|
6ad4ffea3b | ||
|
|
770d51634c | ||
|
|
c51e13941c | ||
|
|
05ae0800c3 | ||
|
|
4bbfe7b3cc | ||
|
|
00530477c9 | ||
|
|
90c1334535 | ||
|
|
83ef031922 | ||
|
|
820c2bc0fd | ||
|
|
a484954d74 | ||
|
|
56be1a4950 | ||
|
|
1e8eb72b2f | ||
|
|
18935bf7f0 | ||
|
|
457c4c248d | ||
|
|
8c553dcde9 | ||
|
|
a709caf138 | ||
|
|
8dea2dab88 | ||
|
|
63aa32c521 | ||
|
|
24841f22f1 | ||
|
|
d712c2f199 | ||
|
|
4525216d26 | ||
|
|
ae61da7485 | ||
|
|
fb9f6153fc | ||
|
|
a0c808842b | ||
|
|
8a8490d97d | ||
|
|
68c7f9840a | ||
|
|
8d37f48744 | ||
|
|
37f32755b5 | ||
|
|
5380fe2483 | ||
|
|
8e71df3e53 | ||
|
|
30f43a245b | ||
|
|
283ed29f10 | ||
|
|
ccd39bb8ae | ||
|
|
db40653202 | ||
|
|
d3940729eb | ||
|
|
56a6ee6afb | ||
|
|
a37a3fc4a1 | ||
|
|
af87cd1dd6 | ||
|
|
e675025411 | ||
|
|
c3d5798c6c | ||
|
|
15d17e16dd | ||
|
|
926061557b | ||
|
|
8522337f32 | ||
|
|
6114f69ee5 | ||
|
|
0aa351443f | ||
|
|
c28ecabfd8 | ||
|
|
bbd779b437 | ||
|
|
b411897a5a | ||
|
|
fb97c30080 | ||
|
|
61b59837bb | ||
|
|
e65c0a9d5e | ||
|
|
3f7674a2e9 | ||
|
|
fb81fc6057 | ||
|
|
e1acb6a547 | ||
|
|
250eb14de1 | ||
|
|
61ae5e16ae | ||
|
|
e1efbfc842 | ||
|
|
7d486cabeb | ||
|
|
c2e953a09f | ||
|
|
59450c7d12 | ||
|
|
ca9e006cca | ||
|
|
387bdb1b84 | ||
|
|
5fb98655b3 | ||
|
|
addfa2f961 | ||
|
|
7679b109cb | ||
|
|
6a418c65ca | ||
|
|
aa55995924 | ||
|
|
5431c269d3 | ||
|
|
73696629d9 | ||
|
|
38b1255119 | ||
|
|
57de11b709 | ||
|
|
ce50533689 | ||
|
|
18ad975573 | ||
|
|
fd8e480363 | ||
|
|
3d6d677453 | ||
|
|
aef8e71b82 | ||
|
|
5872779faa | ||
|
|
04d7907864 | ||
|
|
65a2eccfdb | ||
|
|
4a272afc67 | ||
|
|
2499a6c8a3 | ||
|
|
74ed1ac584 | ||
|
|
d6d48f2866 | ||
|
|
f98b57aa5e | ||
|
|
f114321322 | ||
|
|
940700dc56 | ||
|
|
be0fa98d11 | ||
|
|
e71fc43952 | ||
|
|
cd0f72d66a | ||
|
|
48bb3a9dce | ||
|
|
55d8e801f1 | ||
|
|
54765d2236 | ||
|
|
dbf6716b9b | ||
|
|
a19bb0bbfe | ||
|
|
75a95865ff | ||
|
|
07dd8a2b07 | ||
|
|
8bcfa3660a | ||
|
|
0e4d266a52 | ||
|
|
7676572358 | ||
|
|
7fb758cc1d | ||
|
|
22f0d9cdd3 | ||
|
|
1cb29cea15 | ||
|
|
1eb5d89f1d | ||
|
|
d570552206 | ||
|
|
41f41ee4ee | ||
|
|
94d6f4dae7 | ||
|
|
f30387e7f5 | ||
|
|
3a8b97841f | ||
|
|
df3afb1b89 | ||
|
|
7f935c1ea8 | ||
|
|
7ed94c0410 | ||
|
|
8e15451117 | ||
|
|
111d10fe5c | ||
|
|
98335361fd | ||
|
|
bd36b8a95e | ||
|
|
d89dc967b8 | ||
|
|
dbca9306de | ||
|
|
0cbe08b105 | ||
|
|
af5b19a9da | ||
|
|
da8e4e44b7 | ||
|
|
69666d1089 | ||
|
|
b37d6dcd1c | ||
|
|
c72be6cbf3 | ||
|
|
5a3049485c | ||
|
|
39e77d1823 | ||
|
|
da94ee7a9a | ||
|
|
62ca873ddd | ||
|
|
9404c2309c | ||
|
|
4a2508e960 | ||
|
|
ce6388bdfa | ||
|
|
58d7467180 | ||
|
|
cb53e377a8 | ||
|
|
a3560eb451 | ||
|
|
ef4fd70f9c | ||
|
|
74fe069da9 | ||
|
|
542030f190 | ||
|
|
206b2c6f0b | ||
|
|
dc87592876 | ||
|
|
37f35da436 | ||
|
|
f598da0df2 | ||
|
|
20ccb03a45 | ||
|
|
891362dfb2 | ||
|
|
463cf35e64 | ||
|
|
1919a2d2d6 | ||
|
|
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 |
@@ -0,0 +1,7 @@
|
|||||||
|
[codespell]
|
||||||
|
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
|
||||||
|
skip = .git*,go.sum,*.lock,.codespellrc,vendor,translations,Keybindings_*.md
|
||||||
|
check-hidden = true
|
||||||
|
# camel-cased
|
||||||
|
ignore-regex = (\b[A-Za-z][a-z]*[A-Z]\S+\b|\.edn\b|\S+…|\\nd\b)
|
||||||
|
ignore-words-list = fomrat,inbetween
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*.go text
|
||||||
|
*.md text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
* [ ] 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
|
* [ ] If a new UserConfig entry was added, make sure it can be hot-reloaded (see [here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig))
|
||||||
|
* [ ] 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
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ changelog:
|
|||||||
- title: I18n 🌎
|
- title: I18n 🌎
|
||||||
labels:
|
labels:
|
||||||
- i18n
|
- i18n
|
||||||
|
- title: Performance Improvements 📊
|
||||||
|
labels:
|
||||||
|
- performance
|
||||||
- title: Other Changes
|
- title: Other Changes
|
||||||
labels:
|
labels:
|
||||||
- "*"
|
- "*"
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
name: Continuous Delivery
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
goreleaser:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Unshallow repo
|
|
||||||
run: git fetch --prune --unshallow
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v4
|
|
||||||
with:
|
|
||||||
go-version: 1.20.x
|
|
||||||
- name: Run goreleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v4
|
|
||||||
with:
|
|
||||||
distribution: goreleaser
|
|
||||||
version: v1.17.2
|
|
||||||
args: release --clean
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
|
|
||||||
homebrew:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Bump Homebrew formula
|
|
||||||
uses: dawidd6/action-homebrew-bump-formula@v3
|
|
||||||
with:
|
|
||||||
token: ${{secrets.GITHUB_API_TOKEN}}
|
|
||||||
formula: lazygit
|
|
||||||
+50
-25
@@ -1,7 +1,7 @@
|
|||||||
name: Continuous Integration
|
name: Continuous Integration
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: 1.20
|
GO_VERSION: 1.22
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -28,18 +28,18 @@ 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@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.x
|
go-version: 1.22.x
|
||||||
- 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: |
|
||||||
mkdir -p /tmp/code_coverage
|
mkdir -p /tmp/code_coverage
|
||||||
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
|
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
|
||||||
- name: Upload code coverage artifacts
|
- name: Upload code coverage artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
|
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
|
||||||
path: /tmp/code_coverage
|
path: /tmp/code_coverage
|
||||||
@@ -61,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}}
|
||||||
@@ -82,14 +82,14 @@ 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@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.x
|
go-version: 1.22.x
|
||||||
- name: Print git version
|
- name: Print git version
|
||||||
run: git --version
|
run: git --version
|
||||||
- name: Test code
|
- name: Test code
|
||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
mkdir -p /tmp/code_coverage
|
mkdir -p /tmp/code_coverage
|
||||||
./scripts/run_integration_tests.sh
|
./scripts/run_integration_tests.sh
|
||||||
- name: Upload code coverage artifacts
|
- name: Upload code coverage artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
|
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
|
||||||
path: /tmp/code_coverage
|
path: /tmp/code_coverage
|
||||||
@@ -111,11 +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@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.x
|
go-version: 1.22.x
|
||||||
- name: Build linux binary
|
- name: Build linux binary
|
||||||
run: |
|
run: |
|
||||||
GOOS=linux go build
|
GOOS=linux go build
|
||||||
@@ -138,11 +138,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@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.x
|
go-version: 1.22.x
|
||||||
- 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: |
|
||||||
@@ -164,15 +164,15 @@ 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@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.20.x
|
go-version: 1.22.x
|
||||||
- name: Lint
|
- name: Lint
|
||||||
uses: golangci/golangci-lint-action@v3.7.0
|
uses: golangci/golangci-lint-action@v6.1.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: v1.60
|
||||||
- name: errors
|
- name: errors
|
||||||
run: golangci-lint run
|
run: golangci-lint run
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
@@ -184,17 +184,23 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
mode: exactly
|
mode: exactly
|
||||||
count: 1
|
count: 1
|
||||||
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n"
|
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n, performance"
|
||||||
upload-coverage:
|
upload-coverage:
|
||||||
# List all jobs that produce coverage files
|
# List all jobs that produce coverage files
|
||||||
needs: [unit-tests, integration-tests]
|
needs: [unit-tests, integration-tests]
|
||||||
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||||
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: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22.x
|
||||||
|
|
||||||
- name: Download all coverage artifacts
|
- name: Download all coverage artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: /tmp/code_coverage
|
path: /tmp/code_coverage
|
||||||
|
|
||||||
@@ -213,3 +219,22 @@ jobs:
|
|||||||
CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
|
CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
|
||||||
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
|
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
|
||||||
--force-coverage-parser go -r coverage.out
|
--force-coverage-parser go -r coverage.out
|
||||||
|
|
||||||
|
check-for-fixups:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref != 'refs/heads/master'
|
||||||
|
steps:
|
||||||
|
# See https://github.com/actions/checkout/issues/552#issuecomment-1167086216
|
||||||
|
- name: "PR commits"
|
||||||
|
run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} ))" >> "${GITHUB_ENV}"
|
||||||
|
|
||||||
|
- name: "Checkout PR branch and all PR commits"
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||||
|
ref: ${{ github.event.pull_request.head.ref }}
|
||||||
|
fetch-depth: ${{ env.PR_FETCH_DEPTH }}
|
||||||
|
|
||||||
|
- name: Check for fixups
|
||||||
|
run: |
|
||||||
|
./scripts/check_for_fixups.sh ${{ github.event.pull_request.base.ref }}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Codespell configuration is within .codespellrc
|
||||||
|
---
|
||||||
|
name: Codespell
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codespell:
|
||||||
|
name: Check for spelling errors
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Annotate locations with typos
|
||||||
|
uses: codespell-project/codespell-problem-matcher@v1
|
||||||
|
- name: Codespell
|
||||||
|
uses: codespell-project/actions-codespell@v2
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Runs at 2:00 AM UTC on the first Saturday of every month
|
||||||
|
- cron: '0 2 1-7 * 6'
|
||||||
|
# Allow manual triggering of the workflow
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version_bump:
|
||||||
|
description: 'Version bump type'
|
||||||
|
type: choice
|
||||||
|
required: true
|
||||||
|
default: 'patch'
|
||||||
|
options:
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
ignore_blocks:
|
||||||
|
description: 'Ignore blocking PRs/issues'
|
||||||
|
type: boolean
|
||||||
|
required: true
|
||||||
|
default: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-and-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get Latest Tag
|
||||||
|
run: |
|
||||||
|
latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1) || echo "v0.0.0")
|
||||||
|
|
||||||
|
if ! [[ $latest_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Error: Tag format is invalid. Expected format: vX.X.X"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Latest tag: $latest_tag"
|
||||||
|
echo "latest_tag=$latest_tag" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Check for changes since last release
|
||||||
|
run: |
|
||||||
|
if [ -z "$(git diff --name-only ${{ env.latest_tag }})" ]; then
|
||||||
|
echo "No changes detected since last release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check for Blocking Issues/PRs
|
||||||
|
if: ${{ !inputs.ignore_blocks }}
|
||||||
|
id: check_blocks
|
||||||
|
run: |
|
||||||
|
gh auth setup-git
|
||||||
|
gh auth status
|
||||||
|
|
||||||
|
echo "Checking for blocking issues and PRs..."
|
||||||
|
|
||||||
|
# Check for blocking issues
|
||||||
|
blocking_issues=$(gh issue list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number))"')
|
||||||
|
|
||||||
|
# Check for blocking PRs
|
||||||
|
blocking_prs=$(gh pr list -l blocks-release --json number,title --jq '.[] | "- \(.title) (#\(.number)) (PR)"')
|
||||||
|
|
||||||
|
# Combine the results
|
||||||
|
blocking_items="$blocking_issues"$'\n'"$blocking_prs"
|
||||||
|
|
||||||
|
# Remove empty lines
|
||||||
|
blocking_items=$(echo "$blocking_items" | grep . || true)
|
||||||
|
|
||||||
|
if [ -n "$blocking_items" ]; then
|
||||||
|
echo "Blocking issues/PRs detected:"
|
||||||
|
echo "$blocking_items"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Calculate next version
|
||||||
|
run: |
|
||||||
|
echo "Latest tag: ${{ env.latest_tag }}"
|
||||||
|
IFS='.' read -r major minor patch <<< "${{ env.latest_tag }}"
|
||||||
|
|
||||||
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||||
|
if [[ "${{ inputs.version_bump }}" == "patch" ]]; then
|
||||||
|
patch=$((patch + 1))
|
||||||
|
else
|
||||||
|
minor=$((minor + 1))
|
||||||
|
patch=0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Default behavior for scheduled runs
|
||||||
|
minor=$((minor + 1))
|
||||||
|
patch=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
new_tag="$major.$minor.$patch"
|
||||||
|
|
||||||
|
if ! [[ $new_tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
echo "Error: New tag's format is invalid. Expected format: vX.X.X"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "New tag: $new_tag"
|
||||||
|
echo "new_tag=$new_tag" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create and Push Tag
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git tag ${{ env.new_tag }}
|
||||||
|
git push origin ${{ env.new_tag }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_API_TOKEN }}
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22.x
|
||||||
|
|
||||||
|
- name: Run goreleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v4
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: v1.17.2
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
|
||||||
|
|
||||||
|
- name: Bump Homebrew formula
|
||||||
|
uses: dawidd6/action-homebrew-bump-formula@v3
|
||||||
|
with:
|
||||||
|
token: ${{secrets.GITHUB_API_TOKEN}}
|
||||||
|
formula: lazygit
|
||||||
|
tag: ${{env.new_tag}}
|
||||||
@@ -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.2.2
|
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
|
||||||
|
|||||||
+2
-3
@@ -5,9 +5,7 @@
|
|||||||
|
|
||||||
# Hidden
|
# Hidden
|
||||||
.*
|
.*
|
||||||
|
!.codespellrc
|
||||||
# TODO
|
|
||||||
TODO.*
|
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
*.notes
|
*.notes
|
||||||
@@ -22,6 +20,7 @@ lazygit.exe
|
|||||||
|
|
||||||
# Exceptions
|
# Exceptions
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.gitattributes
|
||||||
!.goreleaser.yml
|
!.goreleaser.yml
|
||||||
!.golangci.yml
|
!.golangci.yml
|
||||||
!.circleci/
|
!.circleci/
|
||||||
|
|||||||
+7
-5
@@ -1,23 +1,25 @@
|
|||||||
linters:
|
linters:
|
||||||
disable:
|
|
||||||
- structcheck # gives false positives
|
|
||||||
enable:
|
enable:
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- thelper
|
- thelper
|
||||||
- goimports
|
- goimports
|
||||||
- tparallel
|
- tparallel
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- exportloopref
|
|
||||||
- unparam
|
- unparam
|
||||||
- prealloc
|
- prealloc
|
||||||
- unconvert
|
- unconvert
|
||||||
- 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:
|
staticcheck:
|
||||||
@@ -30,5 +32,5 @@ linters-settings:
|
|||||||
max-func-lines: 0
|
max-func-lines: 0
|
||||||
|
|
||||||
run:
|
run:
|
||||||
go: '1.20'
|
go: '1.22'
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
|
|||||||
Vendored
+9
@@ -26,6 +26,15 @@
|
|||||||
],
|
],
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "JSON Schema generator",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/pkg/jsonschema/generator.go",
|
||||||
|
"cwd": "${workspaceFolder}/pkg/jsonschema",
|
||||||
|
"console": "integratedTerminal",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Attach to a running Lazygit",
|
"name": "Attach to a running Lazygit",
|
||||||
"type": "go",
|
"type": "go",
|
||||||
|
|||||||
+5
-25
@@ -10,6 +10,10 @@ 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.
|
||||||
|
|
||||||
|
## Design principles
|
||||||
|
|
||||||
|
See [here](./VISION.md) for a set of design principles that we want to consider when building a feature or making a change.
|
||||||
|
|
||||||
## Codebase guide
|
## Codebase guide
|
||||||
|
|
||||||
[This doc](./docs/dev/Codebase_Guide.md) explains:
|
[This doc](./docs/dev/Codebase_Guide.md) explains:
|
||||||
@@ -154,31 +158,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.20 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 ./
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ generate:
|
|||||||
format:
|
format:
|
||||||
gofumpt -l -w .
|
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.
|
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
|
||||||
.PHONY: integration-test-tui
|
.PHONY: integration-test-tui
|
||||||
integration-test-tui:
|
integration-test-tui:
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# Vision and Design Principles
|
||||||
|
|
||||||
|
## Vision
|
||||||
|
|
||||||
|
Lazygit's vision is to be the most enjoyable UI for git.
|
||||||
|
|
||||||
|
## Design Principles
|
||||||
|
|
||||||
|
There are seven (sometimes contradictory) design principles we follow:
|
||||||
|
|
||||||
|
- Dicoverability
|
||||||
|
- Simplicity
|
||||||
|
- Safety
|
||||||
|
- Power
|
||||||
|
- Speed
|
||||||
|
- Conformity with git
|
||||||
|
- Think of the codebase
|
||||||
|
|
||||||
|
### Discoverability
|
||||||
|
|
||||||
|
TUI's are notoriously hard to learn, thanks to limited screen real-estate to provide contextual help and a general lack of effort on the part of developers to make things obvious. We want Lazygit to buck the trend and be easy for a new user to grok.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- Clearly document all the features/configuration options
|
||||||
|
- e.g. gifs in the README
|
||||||
|
- Document how to solve various git problems with Lazygit
|
||||||
|
- This is something we don't have yet but should: a section in the docs explaining how Lazygit can help you in various scenarios
|
||||||
|
- Use tooltips to explain what actions will do
|
||||||
|
- Make it easy for users to ask questions and get answers from the community
|
||||||
|
- Make it easy to find entities and actions from within Lazygit
|
||||||
|
- Use visual elements to make things obvious
|
||||||
|
- e.g. '<-- YOU ARE HERE' label when rebasing
|
||||||
|
- Don't require the user to memorise keybindings
|
||||||
|
- e.g. when the user is mid-rebase, we prominently show that the keybinding for viewing rebase options is 'm'
|
||||||
|
- When the user performs an action in Lazygit, make the impact obvious
|
||||||
|
- If the affected entity isn't visible, show a toast notification
|
||||||
|
- If a keybinding is disabled, give a reason why
|
||||||
|
|
||||||
|
### Simplicity
|
||||||
|
|
||||||
|
The git CLI is very complex but most git use cases are simple. Lazygit needs to ensure that simple use cases are easy to satisfy.
|
||||||
|
|
||||||
|
- Make the most common use cases dead-simple (staging files, committing, pulling/pushing)
|
||||||
|
- Don't overwhelm the user with options
|
||||||
|
- Use sensible defaults
|
||||||
|
- We already have too many configuration options: think hard before adding any new ones
|
||||||
|
|
||||||
|
### Safety
|
||||||
|
|
||||||
|
It's easy to screw things up in git so Lazygit should try to protect the user from screwing things up.
|
||||||
|
|
||||||
|
- Prompt for a confirmation before doing anything that's hard to reverse
|
||||||
|
- Make it easy to correct mistakes
|
||||||
|
- e.g. undo action
|
||||||
|
- the escape key should get you out of most transient situations (rebasing, diffing, etc)
|
||||||
|
|
||||||
|
## Power
|
||||||
|
|
||||||
|
Users shouldn't have to drop down the CLI _too_ often. Lazygit should be able to handle some complex use cases.
|
||||||
|
|
||||||
|
- Make complex (but common) CLI flows simple
|
||||||
|
- e.g. interactive rebasing
|
||||||
|
- Use the custom commands system to handle the really rare complex edge-cases
|
||||||
|
|
||||||
|
### Speed
|
||||||
|
|
||||||
|
Pro users should be able to move at lightning speed with Lazygit.
|
||||||
|
|
||||||
|
- Always think about the number of keypresses involved in a given UX flow
|
||||||
|
- Make lazygit performant and responsive
|
||||||
|
- Think about the individual commands being run and how fast they are
|
||||||
|
- Startup should be FAST. If you want to run something at startup that is slow, make it non-blocking.
|
||||||
|
- Support muscle-memory
|
||||||
|
- Prefer disabling menu items instead of hiding them so that muscle memory can be used to select the desired menu item
|
||||||
|
- Try to make keybinding intuitions to transfer across contexts (e.g. 'd' for destroy)
|
||||||
|
- When changing keybindings in a new release, always consider what will happen if a user does not read the release notes and relies on muscle memory.
|
||||||
|
|
||||||
|
### Conformity with git
|
||||||
|
|
||||||
|
Satisfying the use-cases of git users is more important than perfectly conforming to git's API, but even obscure parts of git's API were motivated by real use-cases.
|
||||||
|
|
||||||
|
- Users should only have to drop down to the git CLI in rare circumstances
|
||||||
|
- Honour the git config
|
||||||
|
- Don't override anything set in the git config without the user's permission
|
||||||
|
- Work with git, not against it.
|
||||||
|
- Too much magic will get us into trouble
|
||||||
|
- Avoid storing Lazygit-specific session state that could instead be stored in git
|
||||||
|
- Ensure that Lazygit can represent the state of any repo
|
||||||
|
- Sometimes git's default behaviour is just silly and we'll make the call to override but it should be a well-considered decision.
|
||||||
|
|
||||||
|
### Think of the codebase
|
||||||
|
|
||||||
|
Will somebody PLEASE think of the codebase!
|
||||||
|
|
||||||
|
Some features are not worth the added complexity in the codebase. The more this codebase grows, the harder it will be to make the changes that everybody wants.
|
||||||
|
|
||||||
|
## Resolving conflicts
|
||||||
|
|
||||||
|
Many of the above objectives are directly antithetical to one another. If you add an extra confirmation prompt for the sake of _safety_, you're sacrificing _speed_. If you support toggling various git flags in the name of _power_, you're sacrificing _simplicity_. There are a few things to say here.
|
||||||
|
|
||||||
|
When there are conflicts, we need to make a judgement call. In general we should err on the side of safety and simplicity as the default, with the ability for users to make things faster / more powerful either through configuration or separate keybindings.
|
||||||
|
|
||||||
|
This does not mean for example that force pushes should be impossible without being manually enabled: force pushes are table stakes for anybody who rebases. But it does mean that a confirmation popup should appear when force pushing.
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+646
-198
@@ -1,10 +1,10 @@
|
|||||||
# User Config
|
# User Config
|
||||||
|
|
||||||
Default path for the config file:
|
Default path for the global 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,10 +16,12 @@ If you want to change the config directory:
|
|||||||
|
|
||||||
- MacOS: `export XDG_CONFIG_HOME="$HOME/.config"`
|
- MacOS: `export XDG_CONFIG_HOME="$HOME/.config"`
|
||||||
|
|
||||||
|
In addition to the global config file you can create repo-specific config files in `<repo>/.git/lazygit.yml`. Settings in these files override settings in the global config file. In addition, files called `.lazygit.yml` in any of the parent directories of a repo will also be loaded; this can be useful if you have settings that you want to apply to a group of repositories.
|
||||||
|
|
||||||
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
|
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://json.schemastore.org/lazygit.json
|
# 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].
|
to the top of your config file or via [Visual Studio Code settings.json config][settings].
|
||||||
@@ -29,249 +31,611 @@ to the top of your config file or via [Visual Studio Code settings.json config][
|
|||||||
|
|
||||||
## Default
|
## Default
|
||||||
|
|
||||||
|
<!-- START CONFIG YAML: AUTOMATICALLY GENERATED with `go generate ./..., DO NOT UPDATE MANUALLY -->
|
||||||
```yaml
|
```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
|
||||||
scrollOffMargin: 2 # how many lines to keep before/after the cursor when it reaches the top/bottom of the view; see 'Scroll-off Margin' section below
|
scrollPastBottom: true
|
||||||
scrollOffBehavior: 'margin' # one of 'margin' | 'jump'; see 'Scroll-off Margin' section below
|
|
||||||
sidePanelWidth: 0.3333 # number from 0 to 1
|
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#scroll-off-margin
|
||||||
|
scrollOffMargin: 2
|
||||||
|
|
||||||
|
# One of: 'margin' (default) | 'jump'
|
||||||
|
scrollOffBehavior: margin
|
||||||
|
|
||||||
|
# The number of spaces per tab; used for everything that's shown in the main view, but probably mostly relevant for diffs.
|
||||||
|
# Note that when using a pager, the pager has its own tab width setting, so you need to pass it separately in the pager command.
|
||||||
|
tabWidth: 4
|
||||||
|
|
||||||
|
# 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'
|
|
||||||
enlargedSideViewLocation: 'left' # one of 'left' | 'top'
|
# The weight of the expanded side panel, relative to the other panels. 2 means
|
||||||
language: 'auto' # one of 'auto' | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
|
# twice as tall as the other panels. Only relevant if `expandFocusedSidePanel` is true.
|
||||||
timeFormat: '02 Jan 06' # https://pkg.go.dev/time#Time.Format
|
expandedSidePanelWeight: 2
|
||||||
shortTimeFormat: '3:04PM'
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# If true, wrap lines in the staging view to the width of the view. This
|
||||||
|
# makes it much easier to work with diffs that have long lines, e.g.
|
||||||
|
# paragraphs of markdown text.
|
||||||
|
wrapLinesInStagingView: true
|
||||||
|
|
||||||
|
# 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
|
- 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 the number of lines changed per file in the Files view
|
||||||
|
showNumstatInFilesView: false
|
||||||
|
|
||||||
|
# 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
|
|
||||||
showBottomLine: true # for hiding the bottom information line (unless it has important information to tell you)
|
# If true, show the command log
|
||||||
showPanelJumps: true # for showing the jump-to-panel keybindings as panel subtitles
|
|
||||||
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.
|
||||||
showFileIcons: true # for hiding file icons in the file views
|
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: 'rounded' # one of 'single' | 'double' | 'rounded' | 'hidden'
|
# One of: 'auto' | 'always'
|
||||||
animateExplosion: true # shows an explosion animation when nuking the working tree
|
# If 'auto', only split the main window when a file has both staged and unstaged changes
|
||||||
portraitMode: 'auto' # one of 'auto' | 'never' | 'always'
|
splitDiff: auto
|
||||||
|
|
||||||
|
# Default size for focused window. Can be changed from within Lazygit with '+' and '_' (but this won't change the default).
|
||||||
|
# One of: 'normal' (default) | 'half' | 'full'
|
||||||
|
screenMode: 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
|
||||||
|
|
||||||
|
# If true, jump to the Files panel after popping a stash
|
||||||
|
switchToFilesAfterStashPop: true
|
||||||
|
|
||||||
|
# If true, jump to the Files panel after applying a stash
|
||||||
|
switchToFilesAfterStashApply: true
|
||||||
|
|
||||||
|
# If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead
|
||||||
|
switchTabsWithPanelJumpKeys: false
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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
|
|
||||||
|
# If true, lazygit will automatically stage files that used to have merge
|
||||||
|
# conflicts but no longer do; and it will also ask you if you want to
|
||||||
|
# continue a merge or rebase if you've resolved all conflicts. If false, it
|
||||||
|
# won't do either of these things.
|
||||||
|
autoStageResolvedConflicts: true
|
||||||
|
|
||||||
|
# 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: Use `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-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
|
||||||
os:
|
|
||||||
copyToClipboardCmd: '' # See 'Custom Command for Copying to Clipboard' section
|
# 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: ""
|
||||||
|
|
||||||
|
# Whether lazygit suspends until an edit process returns
|
||||||
|
editInTerminal: false
|
||||||
|
|
||||||
|
# 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: <disabled> # 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>
|
||||||
executeCustomCommand: ':'
|
confirmInEditor: <a-enter>
|
||||||
createRebaseOptionsMenu: 'm'
|
remove: d
|
||||||
pushFiles: 'P'
|
new: "n"
|
||||||
pullFiles: 'p'
|
edit: e
|
||||||
refresh: 'R'
|
openFile: o
|
||||||
createPatchOptionsMenu: '<c-p>'
|
scrollUpMain: <pgup>
|
||||||
|
scrollDownMain: <pgdown>
|
||||||
|
scrollUpMain-alt1: K
|
||||||
|
scrollDownMain-alt1: J
|
||||||
|
scrollUpMain-alt2: <c-u>
|
||||||
|
scrollDownMain-alt2: <c-d>
|
||||||
|
executeShellCommand: ':'
|
||||||
|
createRebaseOptionsMenu: m
|
||||||
|
|
||||||
|
# 'Files' appended for legacy reasons
|
||||||
|
pushFiles: 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: '{'
|
||||||
toggleRangeSelect: 'v'
|
increaseRenameSimilarityThreshold: )
|
||||||
rangeSelectUp: '<s-up>'
|
decreaseRenameSimilarityThreshold: (
|
||||||
rangeSelectDown: '<s-down>'
|
openDiffTool: <c-t>
|
||||||
status:
|
status:
|
||||||
checkForUpdate: 'u'
|
checkForUpdate: u
|
||||||
recentRepos: '<enter>'
|
recentRepos: <enter>
|
||||||
|
allBranchesLogGraph: a
|
||||||
files:
|
files:
|
||||||
commit: 'c'
|
commitChanges: c
|
||||||
commitWithoutHook: 'w' # commit changes without pre-commit hook
|
commitChangesWithoutHook: w
|
||||||
amendLastCommit: 'A'
|
amendLastCommit: A
|
||||||
commitChangesWithEditor: 'C'
|
commitChangesWithEditor: C
|
||||||
findBaseCommitForFixup: '<c-f>'
|
findBaseCommitForFixup: <c-f>
|
||||||
confirmDiscard: 'x'
|
confirmDiscard: x
|
||||||
ignoreFile: 'i'
|
ignoreFile: i
|
||||||
refreshFiles: 'r'
|
refreshFiles: r
|
||||||
stash: 's'
|
stashAllChanges: s
|
||||||
viewStashOptions: 'S'
|
viewStashOptions: S
|
||||||
toggleStagedAll: 'a' # stage/unstage all
|
toggleStagedAll: a
|
||||||
reset: 'D'
|
viewResetOptions: D
|
||||||
fetch: 'f'
|
fetch: f
|
||||||
toggleTreeView: '`'
|
toggleTreeView: '`'
|
||||||
openMergeTool: 'M'
|
openMergeTool: M
|
||||||
openStatusFilter: '<c-b>'
|
openStatusFilter: <c-b>
|
||||||
|
copyFileInfoToClipboard: "y"
|
||||||
|
collapseAll: '-'
|
||||||
|
expandAll: =
|
||||||
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
|
||||||
merge: 'M'
|
renameBranch: R
|
||||||
viewGitFlowOptions: 'i'
|
mergeIntoCurrentBranch: M
|
||||||
fastForward: 'f' # fast-forward this branch from its upstream
|
viewGitFlowOptions: i
|
||||||
newTag: 'T'
|
fastForward: f
|
||||||
pushTag: 'P'
|
createTag: T
|
||||||
setUpstream: 'u' # set as upstream of checked-out branch
|
pushTag: P
|
||||||
fetch: 'f'
|
setUpstream: u
|
||||||
|
fetchRemote: f
|
||||||
|
sortOrder: s
|
||||||
|
worktrees:
|
||||||
|
viewWorktreeOptions: w
|
||||||
commits:
|
commits:
|
||||||
squash: 's'
|
squashDown: s
|
||||||
reword: 'r'
|
renameCommit: r
|
||||||
rewordWithEditor: 'R'
|
renameCommitWithEditor: R
|
||||||
viewResetOptions: 'g'
|
viewResetOptions: g
|
||||||
fixup: 'f'
|
markCommitAsFixup: f
|
||||||
createFixupCommit: 'F' # create fixup commit for this commit
|
createFixupCommit: F
|
||||||
applyFixupCommits: 'S'
|
squashAboveCommits: S
|
||||||
moveDownCommit: '<c-j>' # move commit down one
|
moveDownCommit: <c-j>
|
||||||
moveUpCommit: '<c-k>' # move commit up one
|
moveUpCommit: <c-k>
|
||||||
amend: 'A'
|
amendToCommit: A
|
||||||
amendCommitAttribute: 'a'
|
resetCommitAuthor: a
|
||||||
pick: 'p' # pick commit (when mid-rebase)
|
pickCommit: p
|
||||||
revert: 't'
|
revertCommit: t
|
||||||
cherryPickCopy: 'C'
|
cherryPickCopy: C
|
||||||
pasteCommits: 'V'
|
pasteCommits: V
|
||||||
tagCommit: 'T'
|
markCommitAsBaseForRebase: B
|
||||||
checkout: '<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:
|
||||||
checkout: 'c'
|
checkoutCommitFile: c
|
||||||
main:
|
main:
|
||||||
toggleSelectHunk: 'a'
|
toggleSelectHunk: a
|
||||||
pickBothHunks: 'b'
|
pickBothHunks: b
|
||||||
|
editSelectHunk: E
|
||||||
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
|
||||||
|
|
||||||
@@ -296,7 +660,14 @@ os:
|
|||||||
open: 'open {{filename}}'
|
open: 'open {{filename}}'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom Command for Copying to Clipboard
|
## Custom Command for Opening a Link
|
||||||
|
```yaml
|
||||||
|
os:
|
||||||
|
openLink: 'bash -C /path/to/your/shell-script.sh {{link}}'
|
||||||
|
```
|
||||||
|
Specify the external command to invoke when opening URL links (i.e. creating MR/PR in GitLab, BitBucket or GitHub). `{{link}}` will be replaced by the URL to be opened. A simple shell script can be used to further mangle the passed URL.
|
||||||
|
|
||||||
|
## Custom Command for Copying to and Pasting from Clipboard
|
||||||
```yaml
|
```yaml
|
||||||
os:
|
os:
|
||||||
copyToClipboardCmd: ''
|
copyToClipboardCmd: ''
|
||||||
@@ -304,11 +675,34 @@ os:
|
|||||||
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.
|
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.
|
||||||
|
|
||||||
If you are working on a terminal that supports OSC52, the following command will let you take advantage of it:
|
If you are working on a terminal that supports OSC52, the following command will let you take advantage of it:
|
||||||
```
|
```yaml
|
||||||
os:
|
os:
|
||||||
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64)\a" > /dev/tty
|
copyToClipboardCmd: printf "\033]52;c;$(printf {{text}} | base64 -w 0)\a" > /dev/tty
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For tmux you need to wrap it with the [tmux escape sequence](https://github.com/tmux/tmux/wiki/FAQ#what-is-the-passthrough-escape-sequence-and-how-do-i-use-it), and enable passthrough in tmux config with `set -g allow-passthrough on`:
|
||||||
|
```yaml
|
||||||
|
os:
|
||||||
|
copyToClipboardCmd: printf "\033Ptmux;\033\033]52;c;$(printf {{text}} | base64 -w 0)\a\033\\" > /dev/tty
|
||||||
|
```
|
||||||
|
|
||||||
|
For the best of both worlds, we can let the command determine if we are running in a tmux session and send the correct sequence:
|
||||||
|
```yaml
|
||||||
|
os:
|
||||||
|
copyToClipboardCmd: >
|
||||||
|
if [[ "$TERM" =~ ^(screen|tmux) ]]; then
|
||||||
|
printf "\033Ptmux;\033\033]52;c;$(printf {{text}} | base64 -w 0)\a\033\\" > /dev/tty
|
||||||
|
else
|
||||||
|
printf "\033]52;c;$(printf {{text}} | base64 -w 0)\a" > /dev/tty
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
A custom command for reading from the clipboard can be set using
|
||||||
|
```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
|
## Configuring File Editing
|
||||||
|
|
||||||
@@ -321,7 +715,7 @@ os:
|
|||||||
editPreset: 'vscode'
|
editPreset: 'vscode'
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
Supported presets are `vim`, `nvim`, `nvim-remote`, `lvim`, `emacs`, `nano`, `micro`, `vscode`, `sublime`, `bbedit`, `kakoune`, `helix`, `xcode`, and `zed`. 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.
|
||||||
|
|
||||||
`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.
|
`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.
|
||||||
|
|
||||||
@@ -362,6 +756,12 @@ That's the behavior when `gui.scrollOffBehavior` is set to "margin" (the default
|
|||||||
|
|
||||||
This setting applies both to all list views (e.g. commits and branches etc), and to the staging view.
|
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)
|
||||||
@@ -433,14 +833,17 @@ gui:
|
|||||||
|
|
||||||
## Custom Branch Color
|
## Custom Branch Color
|
||||||
|
|
||||||
You can customize the color of branches based on the branch prefix:
|
You can customize the color of branches based on branch patterns (regular expressions):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
gui:
|
gui:
|
||||||
branchColors:
|
branchColorPatterns:
|
||||||
'docs': '#11aaff' # use a light blue for branches beginning with 'docs/'
|
'^docs/': '#11aaff' # use a light blue for branches beginning with 'docs/'
|
||||||
|
'ISSUE-\d+': '#ff5733' # use a bright orange for branches containing 'ISSUE-<some-number>'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that the regular expressions are not implicitly anchored to the beginning/end of the branch name. If you want to do that, add leading `^` and/or trailing `$` as needed.
|
||||||
|
|
||||||
## Example Coloring
|
## Example Coloring
|
||||||
|
|
||||||

|

|
||||||
@@ -518,18 +921,63 @@ 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 commit message with prefix that is parsed from the branch name.
|
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.
|
||||||
|
If you define multiple naming patterns, they will be attempted in order until one matches.
|
||||||
|
|
||||||
Example:
|
Example hitting first match:
|
||||||
|
|
||||||
- Branch name: feature/AB-123
|
- Branch name: feature/AB-123
|
||||||
- Commit message: [AB-123] Adding feature
|
- Generated commit message prefix: [AB-123]
|
||||||
|
|
||||||
|
Example hitting second match:
|
||||||
|
|
||||||
|
- Branch name: CD-456_fix_problem
|
||||||
|
- Generated commit message prefix: (CD-456)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
git:
|
||||||
|
commitPrefix:
|
||||||
|
- pattern: "^\\w+\\/(\\w+-\\w+).*"
|
||||||
|
replace: '[$1] '
|
||||||
|
- pattern: "^([^_]+)_.*" # Take all text prior to the first underscore
|
||||||
|
replace: '($1) '
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want repository-specific prefixes, you can map them with `commitPrefixes`. If you have both entries in `commitPrefix` defined and an repository match in `commitPrefixes` for the current repo, the `commitPrefixes` entries will be attempted first. Repository folder names must be an exact match.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
git:
|
git:
|
||||||
commitPrefixes:
|
commitPrefixes:
|
||||||
my_project: # This is repository folder name
|
my_project: # This is repository folder name
|
||||||
pattern: "^\\w+\\/(\\w+-\\w+).*"
|
- pattern: "^\\w+\\/(\\w+-\\w+).*"
|
||||||
replace: '[$1] '
|
replace: '[$1] '
|
||||||
|
commitPrefix:
|
||||||
|
- pattern: "^(\\w+)-.*" # A more general match for any leading word
|
||||||
|
replace : '[$1] '
|
||||||
|
- pattern: ".*" # The final fallthrough regex that copies over the whole branch name
|
||||||
|
replace : '[$0] '
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The way golang regex works is when you use `$n` in the replacement string, where `n` is a number, it puts the nth captured subgroup at that place. If `n` is out of range because there aren't that many capture groups in the regex, it puts an empty string there.
|
||||||
|
>
|
||||||
|
> So make sure you are capturing group or groups in your regex.
|
||||||
|
>
|
||||||
|
> For example `^[A-Z]+-\d+$` won't work on branch name like BRANCH-1111
|
||||||
|
> But `^([A-Z]+-\d+)$` will
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|||||||
@@ -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}}"
|
||||||
@@ -50,7 +50,7 @@ Custom command keybindings will appear alongside inbuilt keybindings when you vi
|
|||||||
For a given custom command, here are the allowed fields:
|
For a given custom command, here are the allowed fields:
|
||||||
| _field_ | _description_ | required |
|
| _field_ | _description_ | required |
|
||||||
|-----------------|----------------------|-|
|
|-----------------|----------------------|-|
|
||||||
| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | yes |
|
| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no |
|
||||||
| command | The command to run (using Go template syntax for placeholder values) | yes |
|
| command | The command to run (using Go template syntax for placeholder values) | yes |
|
||||||
| context | The context in which to listen for the key (see [below](#contexts)) | yes |
|
| context | The context in which to listen for the key (see [below](#contexts)) | yes |
|
||||||
| subprocess | Whether you want the command to run in a subprocess (e.g. if the command requires user input) | no |
|
| subprocess | Whether you want the command to run in a subprocess (e.g. if the command requires user input) | no |
|
||||||
@@ -59,6 +59,7 @@ 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 |
|
| after | Actions to take after the command has completed | no |
|
||||||
|
|
||||||
Here are the options for the `after` key:
|
Here are the options for the `after` key:
|
||||||
@@ -86,6 +87,11 @@ The permitted contexts are:
|
|||||||
| stash | The 'Stash' tab |
|
| stash | The 'Stash' tab |
|
||||||
| global | This keybinding will take affect everywhere |
|
| global | This keybinding will take affect everywhere |
|
||||||
|
|
||||||
|
> **Bonus**
|
||||||
|
>
|
||||||
|
> You can use a comma-separated string, such as `context: 'commits, subCommits'`, to make it effective in multiple contexts.
|
||||||
|
|
||||||
|
|
||||||
## Prompts
|
## Prompts
|
||||||
|
|
||||||
### Common fields
|
### Common fields
|
||||||
@@ -290,9 +296,8 @@ Here's an example using a command but not specifying anything else: so each line
|
|||||||
Your commands can contain placeholder strings using Go's [template syntax](https://jan.newmarch.name/golang/template/chapter-template.html). The template syntax is pretty powerful, letting you do things like conditionals if you want, but for the most part you'll simply want to be accessing the fields on the following objects:
|
Your commands can contain placeholder strings using Go's [template syntax](https://jan.newmarch.name/golang/template/chapter-template.html). The template syntax is pretty powerful, letting you do things like conditionals if you want, but for the most part you'll simply want to be accessing the fields on the following objects:
|
||||||
|
|
||||||
```
|
```
|
||||||
SelectedLocalCommit
|
SelectedCommit
|
||||||
SelectedReflogCommit
|
SelectedCommitRange
|
||||||
SelectedSubCommit
|
|
||||||
SelectedFile
|
SelectedFile
|
||||||
SelectedPath
|
SelectedPath
|
||||||
SelectedLocalBranch
|
SelectedLocalBranch
|
||||||
@@ -305,7 +310,15 @@ 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.
|
(For legacy reasons, `SelectedLocalCommit`, `SelectedReflogCommit`, and `SelectedSubCommit` are also available, but they are deprecated.)
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
We don't support accessing all elements of a range selection yet. We might add this in the future, but as a special case you can access the range of selected commits by using `SelectedCommitRange`, which has two properties `.To` and `.From` which are the hashes of the bottom and top selected commits, respectively. This is useful for passing them to a git command that operates on a range of commits. For example, to create patches for all selected commits, you might use
|
||||||
|
```yml
|
||||||
|
command: "git format-patch {{.SelectedCommitRange.From}}^..{{.SelectedCommitRange.To}}"
|
||||||
|
```
|
||||||
|
|
||||||
## Keybinding collisions
|
## Keybinding collisions
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ git:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
A cool feature of delta is --hyperlinks, which renders clickable links for the line numbers in the left margin, and lazygit supports these. To use them, set the `pager:` config to `delta --dark --paging=never --line-numbers --hyperlinks --hyperlinks-file-link-format="lazygit-edit://{path}:{line}"`; this allows you to click on an underlined line number in the diff to jump right to that same line in your editor.
|
||||||
|
|
||||||
## Diff-so-fancy
|
## Diff-so-fancy
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
+20
-19
@@ -27,6 +27,19 @@ creates a commit with the appropriate subject line.
|
|||||||
Don't confuse this with the lowercase "f" command ("Fixup commit"); that one
|
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.
|
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
|
## Squashing fixup commits
|
||||||
|
|
||||||
When you're ready to merge the branch and want to squash all these fixup commits
|
When you're ready to merge the branch and want to squash all these fixup commits
|
||||||
@@ -43,22 +56,10 @@ 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
|
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.
|
the commit if you haven't published your branch yet.
|
||||||
|
|
||||||
This command works in many cases, and when it does it almost feels like magic,
|
If you have many modifications in your working copy, it is a good idea to stage
|
||||||
but it's important to understand its limitations because it doesn't always work.
|
related changes that are meant to go into the same fixup commit; if no changes
|
||||||
The way it works is that it looks at the deleted lines of your current
|
are staged, ctrl-f works on all unstaged modifications, and then it might show
|
||||||
modifications, blames them to find out which commit those lines come from, and
|
an error if it finds multiple different base commits. If you are interested in
|
||||||
if they all come from the same commit, it selects it. So here are cases where it
|
what the command does to do its magic, and how you can help it work better, you
|
||||||
doesn't work:
|
may want to read the [design document](dev/Find_Base_Commit_For_Fixup_Design.md)
|
||||||
|
that describes this.
|
||||||
- Your current diff has only added lines, but no deleted lines. In this case
|
|
||||||
there's no way for lazygit to know which commit you want to add them to.
|
|
||||||
- The deleted lines belong to multiple different commits. In this case you can
|
|
||||||
help lazygit by staging a set of files or hunks that all belong to the same
|
|
||||||
commit; if some changes are staged, the ctrl-f command works only on those.
|
|
||||||
- The found commit is already on master; in this case, lazygit refuses to select
|
|
||||||
it, because it doesn't make sense to create fixups for it, let alone amend to
|
|
||||||
it.
|
|
||||||
|
|
||||||
To sum it up: the command works great if you are changing code again that you
|
|
||||||
changed or added earlier in the same branch. This is a common enough case to
|
|
||||||
make the command useful.
|
|
||||||
|
|||||||
+11
-11
@@ -1,11 +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)
|
||||||
* [Dev docs](./dev)
|
* [Dev docs](./dev)
|
||||||
* [Keybindings](./keybindings)
|
* [Keybindings](./keybindings)
|
||||||
* [Undo/Redo](./Undoing.md)
|
* [Undo/Redo](./Undoing.md)
|
||||||
* [Range Select](./Range_Select.md)
|
* [Range Select](./Range_Select.md)
|
||||||
* [Searching/Filtering](./Searching.md)
|
* [Searching/Filtering](./Searching.md)
|
||||||
* [Stacked Branches](./Stacked_Branches.md)
|
* [Stacked Branches](./Stacked_Branches.md)
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ 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
|
branch of the stack will "just work" in the sense that it keeps the other
|
||||||
branches properly stacked onto it.
|
branches properly stacked onto it.
|
||||||
|
|
||||||
Lazygit visualizes the invidual branch heads in the stack by marking them with a
|
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
|
cyan asterisk (or a cyan branch symbol if you are using [nerd
|
||||||
fonts](Config.md#display-nerd-fonts-icons)).
|
fonts](Config.md#display-nerd-fonts-icons)).
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## The use-case
|
## The use-case
|
||||||
|
|
||||||
This topic deserves its own doc because there there are a few touch points for it. We have a use-case for knowing when Lazygit is idle or busy because integration tests follow the following process:
|
This topic deserves its own doc because there are a few touch points for it. We have a use-case for knowing when Lazygit is idle or busy because integration tests follow the following process:
|
||||||
1) press a key
|
1) press a key
|
||||||
2) wait until Lazygit is idle
|
2) wait until Lazygit is idle
|
||||||
3) run assertion / press another key
|
3) run assertion / press another key
|
||||||
@@ -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()`.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Packages
|
## 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`: Contains startup code, initialises 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/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/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/git_commands`: All communication to the git binary happens here. So for example there's a `Checkout` method which calls `git checkout`.
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
* `pkg/commands/models`: Contains model structs that represent commits, branches, files, etc.
|
* `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/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/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/config`: Contains code relating to the Lazygit user config. Specifically `pkg/config/user_config/go` defines the user config struct and its default values. See [below](#using-userconfig) for some important information about using it.
|
||||||
* `pkg/constants`: Contains some constant strings (e.g. links to docs)
|
* `pkg/constants`: Contains some constant strings (e.g. links to docs)
|
||||||
* `pkg/env`: Contains code relating to setting/getting environment variables
|
* `pkg/env`: Contains code relating to setting/getting environment variables
|
||||||
* `pkg/i18n`: Contains internationalised strings
|
* `pkg/i18n`: Contains internationalised strings
|
||||||
@@ -86,6 +86,12 @@ The event loop is managed in the `MainLoop` function of `vendor/github.com/jesse
|
|||||||
|
|
||||||
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)`.
|
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)`.
|
||||||
|
|
||||||
|
## Using UserConfig
|
||||||
|
|
||||||
|
The UserConfig struct is loaded from lazygit's global config file (and possibly repo-specific config files). It can be re-loaded while lazygit is running, e.g. when the user edits one of the config files. In this case we should make sure that any new or changed config values take effect immediately. The easiest way to achieve this is what we do in most controllers or helpers: these have a pointer to the `common.Common` struct, which contains the UserConfig, and access it from there. Since the UserConfig instance in `common.Common` is updated whenever we reload the config, the code can be sure that it always uses an up-to-date value, and there's nothing else to do.
|
||||||
|
|
||||||
|
If that's not possible for some reason, see if you can add code to `Gui.onUserConfigLoaded` to update things from the new config; there are some examples in that function to use as a guide. If that's too hard to do too, add the config to the list in `Gui.checkForChangedConfigsThatDontAutoReload` so that the user is asked to quit and restart lazygit.
|
||||||
|
|
||||||
## Legacy code structure
|
## 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).
|
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).
|
||||||
|
|||||||
@@ -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, error
|
||||||
|
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.
|
||||||
@@ -4,3 +4,5 @@
|
|||||||
* [Busy/Idle Tracking](./Busy.md)
|
* [Busy/Idle Tracking](./Busy.md)
|
||||||
* [Integration Tests](../../pkg/integration/README.md)
|
* [Integration Tests](../../pkg/integration/README.md)
|
||||||
* [Demo Recordings](./Demo_Recordings.md)
|
* [Demo Recordings](./Demo_Recordings.md)
|
||||||
|
* [Find base commit for fixup design](Find_Base_Commit_For_Fixup_Design.md)
|
||||||
|
* [Profiling](Profiling.md)
|
||||||
|
|||||||
@@ -20,11 +20,15 @@
|
|||||||
| `<pgup>` | Pgup |
|
| `<pgup>` | Pgup |
|
||||||
| `<pgdown>` | Pgdn |
|
| `<pgdown>` | Pgdn |
|
||||||
| `<up>` | ArrowUp |
|
| `<up>` | ArrowUp |
|
||||||
|
| `<s-up>` | ShiftArrowUp |
|
||||||
| `<down>` | ArrowDown |
|
| `<down>` | ArrowDown |
|
||||||
|
| `<s-down>` | ShiftArrowDown |
|
||||||
| `<left>` | ArrowLeft |
|
| `<left>` | ArrowLeft |
|
||||||
| `<right>` | ArrowRight |
|
| `<right>` | ArrowRight |
|
||||||
| `<tab>` | Tab |
|
| `<tab>` | Tab |
|
||||||
|
| `<backtab>` | Backtab |
|
||||||
| `<enter>` | Enter |
|
| `<enter>` | Enter |
|
||||||
|
| `<a-enter>` | AltEnter |
|
||||||
| `<esc>` | Esc |
|
| `<esc>` | Esc |
|
||||||
| `<backspace>` | Backspace |
|
| `<backspace>` | Backspace |
|
||||||
| `<c-space>` | CtrlSpace |
|
| `<c-space>` | CtrlSpace |
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | 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. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | View custom patch options | |
|
| `` <c-p> `` | View custom patch options | |
|
||||||
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
||||||
| `` _ `` | Prev screen mode | |
|
| `` _ `` | Prev screen mode | |
|
||||||
| `` ? `` | Open keybindings menu | |
|
| `` ? `` | Open keybindings menu | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | Quit | |
|
| `` q `` | Quit | |
|
||||||
@@ -54,6 +56,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy path to clipboard | |
|
| `` <c-o> `` | Copy path to clipboard | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
| `` c `` | Checkout | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
| `` c `` | Checkout | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` o `` | Open file | Open file in default application. |
|
| `` o `` | Open file | Open file in default application. |
|
||||||
@@ -63,6 +66,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | 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. |
|
| `` ` `` | 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. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Search the current view by text | |
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Commit summary
|
## Commit summary
|
||||||
@@ -76,11 +81,11 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
| `` b `` | View bisect options | |
|
| `` b `` | View bisect options | |
|
||||||
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | Reword | Reword the selected commit's message. |
|
| `` r `` | Reword | Reword the selected commit's message. |
|
||||||
| `` R `` | Reword with editor | |
|
| `` R `` | Reword with editor | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
@@ -145,6 +150,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Search the current view by text | |
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Local branches
|
## Local branches
|
||||||
@@ -162,13 +169,14 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | Merge | Merge selected branch into currently checked out branch. |
|
| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
||||||
| `` T `` | New tag | |
|
| `` T `` | New tag | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | Reset | |
|
| `` g `` | Reset | |
|
||||||
| `` R `` | Rename branch | |
|
| `` R `` | Rename branch | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | View commits | |
|
| `` <enter> `` | View commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -230,6 +238,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` c `` | Commit | Commit staged changes. |
|
| `` c `` | Commit | Commit staged changes. |
|
||||||
| `` w `` | Commit changes without pre-commit hook | |
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
| `` C `` | Commit changes using git editor | |
|
| `` C `` | Commit changes using git editor | |
|
||||||
|
| `` <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> |
|
||||||
| `` / `` | Search the current view by text | |
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
@@ -244,7 +253,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Open commit in browser | |
|
| `` o `` | Open commit in browser | |
|
||||||
@@ -262,14 +271,15 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy branch name to clipboard | |
|
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||||
| `` <space> `` | Checkout | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | Checkout | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | New branch | |
|
| `` n `` | New branch | |
|
||||||
| `` M `` | Merge | Merge selected branch into currently checked out branch. |
|
| `` M `` | Merge | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | View commits | |
|
| `` <enter> `` | View commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -306,13 +316,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` e `` | Edit config file | Open file in external editor. |
|
| `` e `` | Edit config file | Open file in external editor. |
|
||||||
| `` u `` | Check for update | |
|
| `` u `` | Check for update | |
|
||||||
| `` <enter> `` | Switch to a recent repo | |
|
| `` <enter> `` | Switch to a recent repo | |
|
||||||
| `` a `` | Show all branch logs | |
|
| `` a `` | Show/cycle all branch logs | |
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Open commit in browser | |
|
| `` o `` | Open commit in browser | |
|
||||||
@@ -343,11 +353,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | Checkout | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | Checkout | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | View commits | |
|
| `` <enter> `` | View commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` @ `` | コマンドログメニューを開く | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | コマンドログメニューを開く | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | カスタムコマンドを実行 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | View custom patch options | |
|
| `` <c-p> `` | View custom patch options | |
|
||||||
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
||||||
| `` _ `` | 前のスクリーンモード | |
|
| `` _ `` | 前のスクリーンモード | |
|
||||||
| `` ? `` | メニューを開く | |
|
| `` ? `` | メニューを開く | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | 終了 | |
|
| `` q `` | 終了 | |
|
||||||
@@ -66,7 +68,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | ブラウザでコミットを開く | |
|
| `` o `` | ブラウザでコミットを開く | |
|
||||||
@@ -93,11 +95,11 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
| `` b `` | View bisect options | |
|
| `` b `` | View bisect options | |
|
||||||
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | コミットメッセージを変更 | Reword the selected commit's message. |
|
| `` r `` | コミットメッセージを変更 | Reword the selected commit's message. |
|
||||||
| `` R `` | エディタでコミットメッセージを編集 | |
|
| `` R `` | エディタでコミットメッセージを編集 | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
@@ -105,7 +107,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` 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.
|
| `` 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.
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
|
| `` p `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
|
||||||
| `` F `` | Create fixup commit | このコミットに対するfixupコミットを作成 |
|
| `` F `` | Fixupコミットを作成 | このコミットに対するfixupコミットを作成 |
|
||||||
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
||||||
| `` <c-j> `` | コミットを1つ下に移動 | |
|
| `` <c-j> `` | コミットを1つ下に移動 | |
|
||||||
| `` <c-k> `` | コミットを1つ上に移動 | |
|
| `` <c-k> `` | コミットを1つ上に移動 | |
|
||||||
@@ -132,6 +134,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
| `` c `` | チェックアウト | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
| `` c `` | チェックアウト | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` o `` | ファイルを開く | Open file in default application. |
|
| `` o `` | ファイルを開く | Open file in default application. |
|
||||||
@@ -141,6 +144,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | 検索を開始 | |
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## コミットメッセージ
|
## コミットメッセージ
|
||||||
@@ -178,11 +183,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | チェックアウト | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | チェックアウト | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | タグを作成 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | タグを作成 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | コミットを閲覧 | |
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -215,6 +222,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | 検索を開始 | |
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## ブランチ
|
## ブランチ
|
||||||
@@ -232,13 +241,14 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | Force checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | 現在のブランチにマージ | Merge selected branch into currently checked out branch. |
|
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
||||||
| `` T `` | タグを作成 | |
|
| `` T `` | タグを作成 | |
|
||||||
| `` s `` | 並び替え | |
|
| `` s `` | 並び替え | |
|
||||||
| `` g `` | Reset | |
|
| `` g `` | Reset | |
|
||||||
| `` R `` | ブランチ名を変更 | |
|
| `` R `` | ブランチ名を変更 | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | コミットを閲覧 | |
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -300,6 +310,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` c `` | 変更をコミット | Commit staged changes. |
|
| `` c `` | 変更をコミット | Commit staged changes. |
|
||||||
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
||||||
| `` C `` | gitエディタを使用して変更をコミット | |
|
| `` 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> |
|
||||||
| `` / `` | 検索を開始 | |
|
| `` / `` | 検索を開始 | |
|
||||||
|
|
||||||
## メニュー
|
## メニュー
|
||||||
@@ -326,14 +337,15 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||||
| `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | 新しいブランチを作成 | |
|
| `` n `` | 新しいブランチを作成 | |
|
||||||
| `` M `` | 現在のブランチにマージ | Merge selected branch into currently checked out branch. |
|
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
| `` s `` | 並び替え | |
|
| `` s `` | 並び替え | |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | コミットを閲覧 | |
|
| `` <enter> `` | コミットを閲覧 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -342,7 +354,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||||
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | ブラウザでコミットを開く | |
|
| `` o `` | ブラウザでコミットを開く | |
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` @ `` | 명령어 로그 메뉴 열기 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | 명령어 로그 메뉴 열기 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | 푸시 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | 푸시 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
| `` p `` | 업데이트 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` p `` | 업데이트 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트의 크기를 늘리기 | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트의 크기를 늘리기 | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기 | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | Diff 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기 | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | 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. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | 커스텀 Patch 옵션 보기 | |
|
| `` <c-p> `` | 커스텀 Patch 옵션 보기 | |
|
||||||
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
|
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
|
||||||
| `` _ `` | 이전 스크린 모드 | |
|
| `` _ `` | 이전 스크린 모드 | |
|
||||||
| `` ? `` | 매뉴 열기 | |
|
| `` ? `` | 매뉴 열기 | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | 종료 | |
|
| `` q `` | 종료 | |
|
||||||
@@ -53,7 +55,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | 브라우저에서 커밋 열기 | |
|
| `` o `` | 브라우저에서 커밋 열기 | |
|
||||||
@@ -83,7 +85,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | 브라우저에서 커밋 열기 | |
|
| `` o `` | 브라우저에서 커밋 열기 | |
|
||||||
@@ -171,6 +173,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
||||||
| `` w `` | Commit changes without pre-commit hook | |
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
| `` C `` | Git 편집기를 사용하여 변경 내용을 커밋합니다. | |
|
| `` 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> |
|
||||||
| `` / `` | 검색 시작 | |
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 브랜치
|
## 브랜치
|
||||||
@@ -186,15 +189,16 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` <c-y> `` | 풀 리퀘스트 URL을 클립보드에 복사 | |
|
| `` <c-y> `` | 풀 리퀘스트 URL을 클립보드에 복사 | |
|
||||||
| `` c `` | 이름으로 체크아웃 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
| `` c `` | 이름으로 체크아웃 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
| `` F `` | 강제 체크아웃 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | 강제 체크아웃 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | 삭제 | View delete options for local/remote branch. |
|
||||||
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | 현재 브랜치에 병합 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | Fast-forward this branch from its upstream | Fast-forward selected branch from its upstream. |
|
| `` f `` | Fast-forward this branch from its upstream | Fast-forward selected branch from its upstream. |
|
||||||
| `` T `` | 태그를 생성 | |
|
| `` T `` | 태그를 생성 | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | View reset options | |
|
| `` g `` | View reset options | |
|
||||||
| `` R `` | 브랜치 이름 변경 | |
|
| `` R `` | 브랜치 이름 변경 | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | 커밋 보기 | |
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -239,14 +243,15 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
|
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
|
||||||
| `` <space> `` | 체크아웃 | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | 체크아웃 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | 새 브랜치 생성 | |
|
| `` n `` | 새 브랜치 생성 | |
|
||||||
| `` M `` | 현재 브랜치에 병합 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 현재 브랜치에 병합 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | 삭제 | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | 커밋 보기 | |
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -255,11 +260,11 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
|
||||||
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
|
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
|
||||||
| `` b `` | Bisect 옵션 보기 | |
|
| `` b `` | Bisect 옵션 보기 | |
|
||||||
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | 스쿼시 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | 커밋메시지 변경 | Reword the selected commit's message. |
|
| `` r `` | 커밋메시지 변경 | Reword the selected commit's message. |
|
||||||
| `` R `` | 에디터에서 커밋메시지 수정 | |
|
| `` R `` | 에디터에서 커밋메시지 수정 | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
@@ -294,6 +299,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
||||||
|
| `` y `` | 클립보드에 복사 | |
|
||||||
| `` c `` | 체크아웃 | Checkout file |
|
| `` c `` | 체크아웃 | Checkout file |
|
||||||
| `` d `` | Remove | Discard this commit's changes to this file |
|
| `` d `` | Remove | Discard this commit's changes to this file |
|
||||||
| `` o `` | 파일 닫기 | Open file in default application. |
|
| `` o `` | 파일 닫기 | Open file in default application. |
|
||||||
@@ -303,6 +309,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | 검색 시작 | |
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 커밋메시지
|
## 커밋메시지
|
||||||
@@ -316,11 +324,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | 체크아웃 | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | 체크아웃 | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | 태그를 생성 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | 태그를 생성 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | 삭제 | View delete options for local/remote tag. |
|
||||||
| `` P `` | 태그를 push | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | 태그를 push | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 초기화 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | 커밋 보기 | |
|
| `` <enter> `` | 커밋 보기 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -332,7 +342,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
|
||||||
| `` <space> `` | Staged 전환 | Toggle staged for selected file. |
|
| `` <space> `` | Staged 전환 | Toggle staged for selected file. |
|
||||||
| `` <c-b> `` | 파일을 필터하기 (Staged/unstaged) | |
|
| `` <c-b> `` | 파일을 필터하기 (Staged/unstaged) | |
|
||||||
| `` y `` | Copy to clipboard | |
|
| `` y `` | 클립보드에 복사 | |
|
||||||
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
| `` c `` | 커밋 변경내용 | Commit staged changes. |
|
||||||
| `` w `` | Commit changes without pre-commit hook | |
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
| `` A `` | 마지맛 커밋 수정 | |
|
| `` A `` | 마지맛 커밋 수정 | |
|
||||||
@@ -348,11 +358,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` d `` | View 'discard changes' options | View options for discarding changes to the selected file. |
|
| `` d `` | View 'discard changes' options | View options for discarding changes to the selected file. |
|
||||||
| `` g `` | View upstream reset options | |
|
| `` g `` | View upstream reset options | |
|
||||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
| `` D `` | 초기화 | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | 검색 시작 | |
|
| `` / `` | 검색 시작 | |
|
||||||
|
|
||||||
## 확인 패널
|
## 확인 패널
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | 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. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | Bekijk aangepaste patch opties | |
|
| `` <c-p> `` | Bekijk aangepaste patch opties | |
|
||||||
| `` m `` | Bekijk merge/rebase opties | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | Bekijk merge/rebase opties | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
|
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
|
||||||
| `` _ `` | Vorige scherm modus | |
|
| `` _ `` | Vorige scherm modus | |
|
||||||
| `` ? `` | Open menu | |
|
| `` ? `` | Open menu | |
|
||||||
| `` <c-s> `` | Bekijk scoping opties | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | Bekijk scoping opties | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | Quit | |
|
| `` q `` | Quit | |
|
||||||
@@ -77,6 +79,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
||||||
| `` f `` | Fetch | Fetch changes from remote. |
|
| `` f `` | Fetch | Fetch changes from remote. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Start met zoeken | |
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Bevestigingspaneel
|
## Bevestigingspaneel
|
||||||
@@ -101,13 +105,14 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` F `` | Forceer checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | Forceer checkout | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | Merge in met huidige checked out branch | Merge selected branch into currently checked out branch. |
|
| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | Fast-forward deze branch vanaf zijn upstream | Fast-forward selected branch from its upstream. |
|
| `` f `` | Fast-forward deze branch vanaf zijn upstream | Fast-forward selected branch from its upstream. |
|
||||||
| `` T `` | Creëer tag | |
|
| `` T `` | Creëer tag | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | Bekijk reset opties | |
|
| `` g `` | Bekijk reset opties | |
|
||||||
| `` R `` | Hernoem branch | |
|
| `` R `` | Hernoem branch | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Bekijk commits | |
|
| `` <enter> `` | Bekijk commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -124,6 +129,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
| `` c `` | Uitchecken | Bestand uitchecken |
|
| `` c `` | Uitchecken | Bestand uitchecken |
|
||||||
| `` d `` | Remove | Uitsluit deze commit zijn veranderingen aan dit bestand |
|
| `` d `` | Remove | Uitsluit deze commit zijn veranderingen aan dit bestand |
|
||||||
| `` o `` | Open bestand | Open file in default application. |
|
| `` o `` | Open bestand | Open file in default application. |
|
||||||
@@ -133,17 +139,19 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | 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. |
|
| `` ` `` | 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. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Start met zoeken | |
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
|
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
|
||||||
| `` b `` | View bisect options | |
|
| `` b `` | View bisect options | |
|
||||||
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | Hernoem commit | Reword the selected commit's message. |
|
| `` r `` | Hernoem commit | Reword the selected commit's message. |
|
||||||
| `` R `` | Hernoem commit met editor | |
|
| `` R `` | Hernoem commit met editor | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
@@ -151,7 +159,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` 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.
|
| `` 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.
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
| `` p `` | Pick | Kies commit (wanneer midden in rebase) |
|
| `` p `` | Pick | Kies commit (wanneer midden in rebase) |
|
||||||
| `` F `` | Create fixup commit | Creëer fixup commit |
|
| `` F `` | Creëer fixup commit | Creëer fixup commit |
|
||||||
| `` S `` | Apply fixup commits | Squash bovenstaande commits |
|
| `` S `` | Apply fixup commits | Squash bovenstaande commits |
|
||||||
| `` <c-j> `` | Verplaats commit 1 naar beneden | |
|
| `` <c-j> `` | Verplaats commit 1 naar beneden | |
|
||||||
| `` <c-k> `` | Verplaats commit 1 naar boven | |
|
| `` <c-k> `` | Verplaats commit 1 naar boven | |
|
||||||
@@ -223,7 +231,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Open commit in browser | |
|
| `` o `` | Open commit in browser | |
|
||||||
@@ -241,14 +249,15 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Kopieer branch name naar klembord | |
|
| `` <c-o> `` | Kopieer branch name naar klembord | |
|
||||||
| `` <space> `` | Uitchecken | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | Uitchecken | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | Nieuwe branch | |
|
| `` n `` | Nieuwe branch | |
|
||||||
| `` M `` | Merge in met huidige checked out branch | Merge selected branch into currently checked out branch. |
|
| `` M `` | Merge in met huidige checked out branch | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | Stel in als upstream van uitgecheckte branch |
|
| `` u `` | Set as upstream | Stel in als upstream van uitgecheckte branch |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Sort order | |
|
||||||
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Bekijk commits | |
|
| `` <enter> `` | Bekijk commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -283,6 +292,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` c `` | Commit veranderingen | Commit staged changes. |
|
| `` c `` | Commit veranderingen | Commit staged changes. |
|
||||||
| `` w `` | Commit veranderingen zonder pre-commit hook | |
|
| `` w `` | Commit veranderingen zonder pre-commit hook | |
|
||||||
| `` C `` | Commit veranderingen met de git editor | |
|
| `` C `` | Commit veranderingen met de git editor | |
|
||||||
|
| `` <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> |
|
||||||
| `` / `` | Start met zoeken | |
|
| `` / `` | Start met zoeken | |
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
@@ -312,7 +322,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
|
||||||
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Open commit in browser | |
|
| `` o `` | Open commit in browser | |
|
||||||
@@ -343,11 +353,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | Uitchecken | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | Uitchecken | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | Creëer tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | Creëer tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Bekijk commits | |
|
| `` <enter> `` | Bekijk commits | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|||||||
+336
-324
@@ -1,146 +1,145 @@
|
|||||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `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
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-r> `` | Switch to a recent repo | |
|
| `` <c-r> `` | Przełącz na ostatnie repozytorium | |
|
||||||
| `` <pgup> (fn+up/shift+k) `` | Scroll up main window | |
|
| `` <pgup> (fn+up/shift+k) `` | Przewiń główne okno w górę | |
|
||||||
| `` <pgdown> (fn+down/shift+j) `` | Scroll down main window | |
|
| `` <pgdown> (fn+down/shift+j) `` | Przewiń główne okno w dół | |
|
||||||
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | Pokaż opcje dziennika poleceń | Pokaż opcje dla dziennika poleceń, np. pokazywanie/ukrywanie dziennika poleceń i skupienie na dzienniku poleceń. |
|
||||||
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` 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. |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` : `` | Wykonaj własną komendę | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
| `` } `` | Zwiększ rozmiar kontekstu w widoku różnic | Zwiększ ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
|
||||||
| `` <c-p> `` | View custom patch options | |
|
| `` { `` | Zmniejsz rozmiar kontekstu w widoku różnic | Zmniejsz ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
|
||||||
| `` m `` | Widok scalenia/opcje zmiany bazy | View options to abort/continue/skip the current merge/rebase. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` R `` | Odśwież | 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`. |
|
| `` <c-p> `` | Wyświetl opcje niestandardowej łatki | |
|
||||||
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
| `` m `` | Pokaż opcje scalania/rebase | Pokaż opcje do przerwania/kontynuowania/pominięcia bieżącego scalania/rebase. |
|
||||||
| `` _ `` | Prev screen mode | |
|
| `` 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`. |
|
||||||
| `` ? `` | Open keybindings menu | |
|
| `` + `` | Następny tryb ekranu (normalny/półpełny/pełnoekranowy) | |
|
||||||
| `` <c-s> `` | View filter-by-path options | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` _ `` | Poprzedni tryb ekranu | |
|
||||||
| `` 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. |
|
| `` ? `` | Otwórz menu przypisań klawiszy | |
|
||||||
| `` <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. |
|
| `` <c-s> `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. |
|
||||||
| `` q `` | Quit | |
|
| `` 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. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` q `` | Wyjdź | |
|
||||||
| `` <esc> `` | Anuluj | |
|
| `` <esc> `` | Anuluj | |
|
||||||
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
|
| `` <c-w> `` | Przełącz białe znaki | Przełącz czy zmiany białych znaków są pokazywane w widoku różnic. |
|
||||||
| `` 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. |
|
| `` 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> `` | 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. |
|
| `` <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
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` , `` | Previous page | |
|
| `` , `` | Poprzednia strona | |
|
||||||
| `` . `` | Next page | |
|
| `` . `` | Następna strona | |
|
||||||
| `` < `` | Scroll to top | |
|
| `` < `` | Przewiń do góry | |
|
||||||
| `` > `` | Scroll to bottom | |
|
| `` > `` | Przewiń do dołu | |
|
||||||
| `` v `` | Toggle range select | |
|
| `` v `` | Przełącz zaznaczenie zakresu | |
|
||||||
| `` <s-down> `` | Range select down | |
|
| `` <s-down> `` | Zaznacz zakres w dół | |
|
||||||
| `` <s-up> `` | Range select up | |
|
| `` <s-up> `` | Zaznacz zakres w górę | |
|
||||||
| `` / `` | Search the current view by text | |
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
| `` H `` | Scroll left | |
|
| `` H `` | Przewiń w lewo | |
|
||||||
| `` L `` | Scroll right | |
|
| `` L `` | Przewiń w prawo | |
|
||||||
| `` ] `` | Next tab | |
|
| `` ] `` | Następna zakładka | |
|
||||||
| `` [ `` | Previous tab | |
|
| `` [ `` | Poprzednia zakładka | |
|
||||||
|
|
||||||
## Commit summary
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <enter> `` | Potwierdź | |
|
|
||||||
| `` <esc> `` | Zamknij | |
|
|
||||||
|
|
||||||
## Commity
|
## Commity
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
| `` b `` | View bisect options | |
|
| `` b `` | Zobacz opcje bisect | |
|
||||||
| `` s `` | Spłaszcz | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | Scal | Scal wybrany commit z commitami poniżej. Wiadomość wybranego commita zostanie dołączona do commita poniżej. |
|
||||||
| `` f `` | Napraw | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Poprawka | Włącz wybrany commit do commita poniżej. Podobnie do fixup, ale wiadomość wybranego commita zostanie odrzucona. |
|
||||||
| `` r `` | Zmień nazwę commita | Reword the selected commit's message. |
|
| `` r `` | Przeformułuj | Przeformułuj wiadomość wybranego commita. |
|
||||||
| `` R `` | Zmień nazwę commita w edytorze | |
|
| `` R `` | Przeformułuj za pomocą edytora | |
|
||||||
| `` d `` | Usuń 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. |
|
| `` 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. |
|
||||||
| `` e `` | Edit (start interactive rebase) | Edytuj commit |
|
| `` 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. |
|
||||||
| `` 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.
|
| `` 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.
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, naciśnij `e`. |
|
||||||
| `` p `` | Pick | Wybierz commit (podczas zmiany bazy) |
|
| `` p `` | Wybierz | Oznacz wybrany commit do wybrania (podczas rebazowania). Oznacza to, że commit zostanie zachowany po kontynuacji rebazowania. |
|
||||||
| `` F `` | Create fixup commit | Utwórz commit naprawczy dla tego commita |
|
| `` 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. |
|
||||||
| `` S `` | Apply fixup commits | Spłaszcz wszystkie commity naprawcze powyżej zaznaczonych commitów (autosquash) |
|
| `` S `` | Zastosuj commity fixup | Scal wszystkie commity 'fixup!', albo powyżej wybranego commita, albo wszystkie w bieżącej gałęzi (autosquash). |
|
||||||
| `` <c-j> `` | Przenieś commit 1 w dół | |
|
| `` <c-j> `` | Przesuń commit w dół | |
|
||||||
| `` <c-k> `` | Przenieś commit 1 w górę | |
|
| `` <c-k> `` | Przesuń commit w górę | |
|
||||||
| `` V `` | Wklej commity (przebieranie) | |
|
| `` V `` | Wklej (cherry-pick) | |
|
||||||
| `` 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. |
|
| `` 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`. |
|
||||||
| `` A `` | Amend | Popraw commit zmianami z poczekalni |
|
| `` 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. |
|
||||||
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
| `` a `` | Popraw atrybut commita | Ustaw/Resetuj autora commita lub ustaw współautora. |
|
||||||
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
| `` t `` | Cofnij | Utwórz commit cofający dla wybranego commita, który stosuje zmiany wybranego commita w odwrotnej kolejności. |
|
||||||
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
| `` T `` | Otaguj commit | Utwórz nowy tag wskazujący na wybrany commit. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
|
||||||
| `` <c-l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
| `` <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. |
|
||||||
| `` <space> `` | Przełącz | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
| `` o `` | Open commit in browser | |
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
| `` n `` | Create new branch off of commit | |
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
| `` g `` | Wyświetl opcje resetu | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
| `` C `` | Kopiuj commit (przebieranie) | 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 `` | 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> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
| `` <enter> `` | Przeglądaj pliki commita | |
|
| `` <enter> `` | Wyświetl pliki | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
| `` / `` | Search the current view by text | |
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
## Confirmation panel
|
## Drzewa pracy
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | Potwierdź | |
|
| `` n `` | Nowe drzewo pracy | |
|
||||||
| `` <esc> `` | Zamknij | |
|
| `` <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)
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Copy branch name to clipboard | |
|
| `` <left> `` | Idź do poprzedniego fragmentu | |
|
||||||
| `` i `` | Show git-flow options | |
|
| `` <right> `` | Idź do następnego fragmentu | |
|
||||||
| `` <space> `` | Przełącz | Checkout selected item. |
|
| `` v `` | Przełącz zaznaczenie zakresu | |
|
||||||
|
| `` a `` | Zaznacz fragment | Przełącz tryb zaznaczania fragmentu. |
|
||||||
|
| `` <c-o> `` | Kopiuj zaznaczony tekst do schowka | |
|
||||||
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` <space> `` | Przełącz linie w łatce | |
|
||||||
|
| `` <esc> `` | Wyjdź z budowniczego niestandardowej łatki | |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
|
## Lokalne gałęzie
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj nazwę gałęzi do schowka | |
|
||||||
|
| `` i `` | Pokaż opcje git-flow | |
|
||||||
|
| `` <space> `` | Przełącz | Przełącz wybrany element. |
|
||||||
| `` n `` | Nowa gałąź | |
|
| `` n `` | Nowa gałąź | |
|
||||||
| `` o `` | Utwórz żądanie pobrania | |
|
| `` o `` | Utwórz żądanie ściągnięcia | |
|
||||||
| `` O `` | Utwórz opcje żądania ściągnięcia | |
|
| `` O `` | Zobacz opcje tworzenia pull requesta | |
|
||||||
| `` <c-y> `` | Skopiuj adres URL żądania pobrania do schowka | |
|
| `` <c-y> `` | Kopiuj adres URL żądania ściągnięcia do schowka | |
|
||||||
| `` c `` | Przełącz używając nazwy | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
| `` c `` | Przełącz według nazwy | Przełącz według nazwy. W polu wprowadzania możesz wpisać '-' aby przełączyć się na ostatnią gałąź. |
|
||||||
| `` F `` | Wymuś przełączenie | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` 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łąź. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnej/odległej gałęzi. |
|
||||||
| `` r `` | Zmiana bazy gałęzi | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Przebazuj | Przebazuj przełączoną gałąź na wybraną gałąź. |
|
||||||
| `` M `` | Scal do obecnej gałęzi | Merge selected branch into currently checked out branch. |
|
| `` M `` | Scal | Scal wybraną gałąź z aktualnie sprawdzoną gałęzią. |
|
||||||
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
| `` f `` | Szybkie przewijanie | Szybkie przewijanie wybranej gałęzi z jej źródła. |
|
||||||
| `` T `` | New tag | |
|
| `` T `` | Nowy tag | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | Kolejność sortowania | |
|
||||||
| `` g `` | Wyświetl opcje resetu | |
|
| `` g `` | Reset | |
|
||||||
| `` R `` | Rename branch | |
|
| `` R `` | Zmień nazwę gałęzi | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | Pokaż opcje upstream | Pokaż opcje dotyczące upstream gałęzi, np. ustawianie/usuwanie upstream i resetowanie do upstream. |
|
||||||
| `` <enter> `` | View commits | |
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
| `` w `` | View worktree options | |
|
| `` <enter> `` | Pokaż commity | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
## Main panel (patch building)
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <left> `` | Poprzedni kawałek | |
|
|
||||||
| `` <right> `` | Następny kawałek | |
|
|
||||||
| `` v `` | Toggle range select | |
|
|
||||||
| `` a `` | Select hunk | Toggle hunk selection mode. |
|
|
||||||
| `` <c-o> `` | Copy selected text to clipboard | |
|
|
||||||
| `` o `` | Otwórz plik | Open file in default application. |
|
|
||||||
| `` e `` | Edytuj plik | Open file in external editor. |
|
|
||||||
| `` <space> `` | Toggle lines in patch | |
|
|
||||||
| `` <esc> `` | Wyście z trybu "linia po linii" | |
|
|
||||||
| `` / `` | Search the current view by text | |
|
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
|
|
||||||
@@ -148,216 +147,229 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | Wykonaj | |
|
| `` <enter> `` | Wykonaj | |
|
||||||
| `` <esc> `` | Zamknij | |
|
| `` <esc> `` | Zamknij | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
## Pliki
|
## Panel główny (normalny)
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy path to clipboard | |
|
|
||||||
| `` <space> `` | Przełącz stan poczekalni | Toggle staged for selected file. |
|
|
||||||
| `` <c-b> `` | Filter files by status | |
|
|
||||||
| `` y `` | Copy to clipboard | |
|
|
||||||
| `` c `` | Zatwierdź zmiany | Commit staged changes. |
|
|
||||||
| `` w `` | Zatwierdź zmiany bez skryptu pre-commit | |
|
|
||||||
| `` A `` | Zmień ostatni commit | |
|
|
||||||
| `` C `` | Zatwierdź zmiany używając edytora | |
|
|
||||||
| `` <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> |
|
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
|
||||||
| `` o `` | Otwórz plik | Open file in default application. |
|
|
||||||
| `` i `` | Ignore or exclude file | |
|
|
||||||
| `` r `` | Odśwież pliki | |
|
|
||||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
|
||||||
| `` S `` | Wyświetl opcje schowka | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
|
||||||
| `` a `` | Przełącz stan poczekalni wszystkich | Toggle staged/unstaged for all files in working tree. |
|
|
||||||
| `` <enter> `` | Zatwierdź pojedyncze linie | 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. |
|
|
||||||
| `` d `` | Pokaż opcje porzucania zmian | View options for discarding changes to the selected file. |
|
|
||||||
| `` g `` | View upstream reset options | |
|
|
||||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
|
||||||
| `` ` `` | 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. |
|
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
|
||||||
| `` f `` | Pobierz | Fetch changes from remote. |
|
|
||||||
| `` / `` | Search the current view by text | |
|
|
||||||
|
|
||||||
## Pliki commita
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy path to clipboard | |
|
|
||||||
| `` c `` | Przełącz | Plik wybierania |
|
|
||||||
| `` d `` | Remove | Porzuć zmiany commita dla tego pliku |
|
|
||||||
| `` o `` | Otwórz plik | Open file in default application. |
|
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
|
||||||
| `` <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. |
|
|
||||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
|
||||||
| `` <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. |
|
|
||||||
| `` ` `` | 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 | |
|
|
||||||
|
|
||||||
## Poczekalnia
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <left> `` | Poprzedni kawałek | |
|
|
||||||
| `` <right> `` | Następny kawałek | |
|
|
||||||
| `` v `` | Toggle range select | |
|
|
||||||
| `` a `` | Select hunk | Toggle hunk selection mode. |
|
|
||||||
| `` <c-o> `` | Copy selected text to clipboard | |
|
|
||||||
| `` <space> `` | Przełącz stan poczekalni | Toggle selection staged / unstaged. |
|
|
||||||
| `` d `` | Discard | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
|
||||||
| `` o `` | Otwórz plik | Open file in default application. |
|
|
||||||
| `` e `` | Edytuj plik | Open file in external editor. |
|
|
||||||
| `` <esc> `` | Wróć do panelu plików | |
|
|
||||||
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
|
|
||||||
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
|
||||||
| `` c `` | Zatwierdź zmiany | Commit staged changes. |
|
|
||||||
| `` w `` | Zatwierdź zmiany bez skryptu pre-commit | |
|
|
||||||
| `` C `` | Zatwierdź zmiany używając edytora | |
|
|
||||||
| `` / `` | Search the current view by text | |
|
|
||||||
|
|
||||||
## Reflog
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
|
||||||
| `` <space> `` | Przełącz | Checkout the selected commit as a detached HEAD. |
|
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
|
||||||
| `` o `` | Open commit in browser | |
|
|
||||||
| `` n `` | Create new branch off of commit | |
|
|
||||||
| `` g `` | Wyświetl opcje resetu | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
|
||||||
| `` C `` | Kopiuj commit (przebieranie) | 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> `` | Reset copied (cherry-picked) commits selection | |
|
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
|
||||||
| `` <enter> `` | View commits | |
|
|
||||||
| `` w `` | View worktree options | |
|
|
||||||
| `` / `` | Filter the current view by text | |
|
|
||||||
|
|
||||||
## Remote branches
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy branch name to clipboard | |
|
|
||||||
| `` <space> `` | Przełącz | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
|
||||||
| `` n `` | Nowa gałąź | |
|
|
||||||
| `` M `` | Scal do obecnej gałęzi | Merge selected branch into currently checked out branch. |
|
|
||||||
| `` r `` | Zmiana bazy gałęzi | Rebase the checked-out branch onto the selected branch. |
|
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
|
||||||
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
|
||||||
| `` s `` | Sort order | |
|
|
||||||
| `` g `` | Wyświetl opcje resetu | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
|
||||||
| `` <enter> `` | View commits | |
|
|
||||||
| `` w `` | View worktree options | |
|
|
||||||
| `` / `` | Filter the current view by text | |
|
|
||||||
|
|
||||||
## Remotes
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <enter> `` | View branches | |
|
|
||||||
| `` n `` | New remote | |
|
|
||||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
|
||||||
| `` e `` | Edit | Edit the selected remote's name or URL. |
|
|
||||||
| `` f `` | Pobierz | 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 | |
|
|
||||||
|
|
||||||
## Scalanie
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <space> `` | Wybierz kawałek | |
|
|
||||||
| `` b `` | Wybierz oba kawałki | |
|
|
||||||
| `` <up> `` | Wybierz poprzedni kawałek | |
|
|
||||||
| `` <down> `` | Wybierz następny kawałek | |
|
|
||||||
| `` <left> `` | Poprzedni konflikt | |
|
|
||||||
| `` <right> `` | Następny konflikt | |
|
|
||||||
| `` z `` | Cofnij | Undo last merge conflict resolution. |
|
|
||||||
| `` e `` | Edytuj plik | Open file in external editor. |
|
|
||||||
| `` o `` | Otwórz plik | Open file in default application. |
|
|
||||||
| `` M `` | Open external merge tool | Run `git mergetool`. |
|
|
||||||
| `` <esc> `` | Wróć do panelu plików | |
|
|
||||||
|
|
||||||
## Schowek
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <space> `` | Zastosuj | Apply the stash entry to your working directory. |
|
|
||||||
| `` g `` | Wyciągnij | Apply the stash entry to your working directory and remove the stash entry. |
|
|
||||||
| `` d `` | Porzuć | Remove the stash entry from the stash list. |
|
|
||||||
| `` n `` | Nowa gałąź | 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. |
|
|
||||||
| `` r `` | Rename stash | |
|
|
||||||
| `` <enter> `` | Przeglądaj pliki commita | |
|
|
||||||
| `` w `` | View worktree options | |
|
|
||||||
| `` / `` | Filter the current view by text | |
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` o `` | Otwórz konfigurację | Open file in default application. |
|
|
||||||
| `` e `` | Edytuj konfigurację | Open file in external editor. |
|
|
||||||
| `` u `` | Sprawdź aktualizacje | |
|
|
||||||
| `` <enter> `` | Switch to a recent repo | |
|
|
||||||
| `` a `` | Pokaż wszystkie logi gałęzi | |
|
|
||||||
|
|
||||||
## Sub-commits
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy commit SHA to clipboard | |
|
|
||||||
| `` <space> `` | Przełącz | Checkout the selected commit as a detached HEAD. |
|
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
|
||||||
| `` o `` | Open commit in browser | |
|
|
||||||
| `` n `` | Create new branch off of commit | |
|
|
||||||
| `` g `` | Wyświetl opcje resetu | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
|
||||||
| `` C `` | Kopiuj commit (przebieranie) | 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> `` | Reset copied (cherry-picked) commits selection | |
|
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
|
||||||
| `` <enter> `` | Przeglądaj pliki commita | |
|
|
||||||
| `` w `` | View worktree options | |
|
|
||||||
| `` / `` | Search the current view by text | |
|
|
||||||
|
|
||||||
## Submodules
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | Copy submodule name to clipboard | |
|
|
||||||
| `` <enter> `` | Enter | Enter submodule. After entering the submodule, you can press `<esc>` to escape back to the parent repo. |
|
|
||||||
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
|
||||||
| `` u `` | Update | Update selected submodule. |
|
|
||||||
| `` n `` | New submodule | |
|
|
||||||
| `` e `` | Update submodule URL | |
|
|
||||||
| `` 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. |
|
|
||||||
| `` b `` | View bulk submodule options | |
|
|
||||||
| `` / `` | Filter the current view by text | |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <space> `` | Przełącz | Checkout the selected tag tag as a detached HEAD. |
|
|
||||||
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
|
||||||
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
|
||||||
| `` <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 | |
|
|
||||||
|
|
||||||
## Zwykłe
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` mouse wheel down (fn+up) `` | Przewiń w dół | |
|
| `` mouse wheel down (fn+up) `` | Przewiń w dół | |
|
||||||
| `` mouse wheel up (fn+down) `` | Przewiń w górę | |
|
| `` 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
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj ścieżkę do schowka | |
|
||||||
|
| `` <space> `` | Zatwierdź | Przełącz zatwierdzenie dla wybranego pliku. |
|
||||||
|
| `` <c-b> `` | Filtruj pliki według statusu | |
|
||||||
|
| `` y `` | Kopiuj do schowka | |
|
||||||
|
| `` c `` | Commit | Zatwierdź zmiany zatwierdzone. |
|
||||||
|
| `` w `` | Zatwierdź zmiany bez hooka pre-commit | |
|
||||||
|
| `` A `` | Popraw ostatni 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> |
|
||||||
|
| `` e `` | Edytuj | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` i `` | Ignoruj lub wyklucz plik | |
|
||||||
|
| `` r `` | Odśwież pliki | |
|
||||||
|
| `` s `` | Schowaj | Schowaj wszystkie zmiany. Dla innych wariantów schowania, użyj klawisza wyświetlania opcji schowka. |
|
||||||
|
| `` S `` | Wyświetl opcje schowka | Wyświetl opcje schowka (np. schowaj wszystko, schowaj zatwierdzone, schowaj niezatwierdzone). |
|
||||||
|
| `` a `` | Zatwierdź wszystko | Przełącz zatwierdzenie/odznaczenie dla wszystkich plików w drzewie roboczym. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` d `` | Odrzuć | Wyświetl opcje odrzucania zmian w wybranym pliku. |
|
||||||
|
| `` g `` | Pokaż opcje resetowania do upstream | |
|
||||||
|
| `` D `` | Reset | Wyświetl opcje resetu dla drzewa roboczego (np. zniszczenie drzewa roboczego). |
|
||||||
|
| `` ` `` | 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. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
|
## Pliki commita
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj ścieżkę do schowka | |
|
||||||
|
| `` y `` | Kopiuj do schowka | |
|
||||||
|
| `` c `` | Przełącz | Przełącz plik. Zastępuje plik w twoim drzewie roboczym wersją z wybranego commita. |
|
||||||
|
| `` 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. |
|
||||||
|
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` e `` | Edytuj | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
|
||||||
|
| `` <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. |
|
||||||
|
| `` a `` | Przełącz wszystkie pliki | Dodaj/usuń wszystkie pliki commita do niestandardowej łatki. Zobacz https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` ` `` | 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. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | Szukaj w bieżącym widoku po tekście | |
|
||||||
|
|
||||||
|
## Podsumowanie commita
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Potwierdź | |
|
||||||
|
| `` <esc> `` | Zamknij | |
|
||||||
|
|
||||||
|
## Reflog
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
|
| `` 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-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
|
| `` <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 | |
|
||||||
|
|
||||||
|
## Schowek
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <space> `` | Zastosuj | Zastosuj wpis schowka do katalogu roboczego. |
|
||||||
|
| `` g `` | Wyciągnij | Zastosuj wpis schowka do katalogu roboczego i usuń wpis schowka. |
|
||||||
|
| `` d `` | Usuń | Usuń wpis schowka z listy schowka. |
|
||||||
|
| `` 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. |
|
||||||
|
| `` r `` | Zmień nazwę schowka | |
|
||||||
|
| `` <enter> `` | Wyświetl pliki | |
|
||||||
|
| `` w `` | Zobacz opcje drzewa pracy | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` o `` | Otwórz plik konfiguracyjny | Otwórz plik w domyślnej aplikacji. |
|
||||||
|
| `` e `` | Edytuj plik konfiguracyjny | Otwórz plik w zewnętrznym edytorze. |
|
||||||
|
| `` u `` | Sprawdź aktualizacje | |
|
||||||
|
| `` <enter> `` | Przełącz na ostatnie repozytorium | |
|
||||||
|
| `` a `` | Pokaż wszystkie gałęzie w logach | |
|
||||||
|
|
||||||
|
## Sub-commity
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
|
||||||
|
| `` <space> `` | Przełącz | Przełącz wybrany commit jako odłączoną HEAD. |
|
||||||
|
| `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). |
|
||||||
|
| `` o `` | Otwórz commit w przeglądarce | |
|
||||||
|
| `` n `` | Utwórz nową gałąź z commita | |
|
||||||
|
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
|
||||||
|
| `` 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-r> `` | Resetuj wybrane (cherry-picked) commity | |
|
||||||
|
| `` <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 | |
|
||||||
|
|
||||||
|
## Submoduły
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Kopiuj nazwę submodułu do schowka | |
|
||||||
|
| `` <enter> `` | Wejdź | Wejdź do submodułu. Po wejściu do submodułu możesz nacisnąć `<esc>`, aby wrócić do repozytorium nadrzędnego. |
|
||||||
|
| `` d `` | Usuń | Usuń wybrany submoduł i odpowiadający mu katalog. |
|
||||||
|
| `` u `` | Aktualizuj | Aktualizuj wybrany submoduł. |
|
||||||
|
| `` n `` | Nowy submoduł | |
|
||||||
|
| `` e `` | Zaktualizuj URL submodułu | |
|
||||||
|
| `` i `` | Zainicjuj | Zainicjuj wybrany submoduł, aby przygotować do pobrania. Prawdopodobnie chcesz to kontynuować, wywołując akcję 'update', aby pobrać submoduł. |
|
||||||
|
| `` b `` | Pokaż opcje masowych operacji na submodułach | |
|
||||||
|
| `` / `` | Filtruj bieżący widok po tekście | |
|
||||||
|
|
||||||
|
## Tagi
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | Przełącz | Przełącz wybrany tag jako odłączoną głowę (detached HEAD). |
|
||||||
|
| `` n `` | Nowy tag | Utwórz nowy tag z bieżącego commita. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
|
||||||
|
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnego/odległego tagu. |
|
||||||
|
| `` P `` | Wyślij tag | Wyślij wybrany tag do zdalnego. Zostaniesz poproszony o wybranie zdalnego. |
|
||||||
|
| `` 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 | |
|
||||||
|
|
||||||
|
## Zdalne
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Wyświetl gałęzie | |
|
||||||
|
| `` 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 | |
|
||||||
|
|||||||
@@ -0,0 +1,379 @@
|
|||||||
|
_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
|
||||||
|
|
||||||
|
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||||
|
|
||||||
|
## Combinações globais de teclas
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-r> `` | Mudar para um repositório recente | |
|
||||||
|
| `` <pgup> (fn+up/shift+k) `` | Scroll up main window | |
|
||||||
|
| `` <pgdown> (fn+down/shift+j) `` | Scroll down main window | |
|
||||||
|
| `` @ `` | View command log options | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
|
| `` P `` | Empurre (Push) | Faça push do branch atual para o seu branch upstream. Se nenhum upstream estiver configurado, você será solicitado a configurar um branch a montante. |
|
||||||
|
| `` p `` | Puxar (Pull) | Puxe alterações do controle remoto para o ramo atual. Se nenhum upstream estiver configurado, será solicitado configurar um ramo a montante. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||||
|
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
|
| `` <c-p> `` | View custom patch options | |
|
||||||
|
| `` m `` | Ver opções de mesclar/rebase | Ver opções para abortar/continuar/pular o merge/rebase atual. |
|
||||||
|
| `` R `` | Atualizar | Atualize o estado do git (ou seja, execute `git status`, `git branch`, etc em segundo plano para atualizar o conteúdo de painéis). Isso não executa `git fetch`. |
|
||||||
|
| `` + `` | Next screen mode (normal/half/fullscreen) | |
|
||||||
|
| `` _ `` | Prev screen mode | |
|
||||||
|
| `` ? `` | Open keybindings menu | |
|
||||||
|
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
|
| `` 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. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` q `` | Sair | |
|
||||||
|
| `` <esc> `` | Cancel | |
|
||||||
|
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
|
| `` z `` | Desfazer | O reflog será usado para determinar qual comando git para executar para desfazer o último comando git. Isto não inclui mudanças na árvore de trabalho; apenas compromissos são tidos em consideração. |
|
||||||
|
| `` <c-z> `` | Refazer | O reflog será usado para determinar qual comando git para executar para refazer o último comando git. Isto não inclui mudanças na árvore de trabalho; apenas compromissos são tidos em consideração. |
|
||||||
|
|
||||||
|
## List panel navigation
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` , `` | Previous page | |
|
||||||
|
| `` . `` | Next page | |
|
||||||
|
| `` < `` | Scroll to top | |
|
||||||
|
| `` > `` | Scroll to bottom | |
|
||||||
|
| `` v `` | Toggle range select | |
|
||||||
|
| `` <s-down> `` | Range select down | |
|
||||||
|
| `` <s-up> `` | Range select up | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
| `` H `` | Scroll left | |
|
||||||
|
| `` L `` | Scroll right | |
|
||||||
|
| `` ] `` | Next tab | |
|
||||||
|
| `` [ `` | Previous tab | |
|
||||||
|
|
||||||
|
## Arquivos
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy path to clipboard | |
|
||||||
|
| `` <space> `` | Etapa | Alternar para staging para o arquivo selecionado. |
|
||||||
|
| `` <c-b> `` | Filtrar arquivos por status | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
|
| `` c `` | Commit | Submeter mudanças em staging |
|
||||||
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
|
| `` A `` | Alterar último commit | |
|
||||||
|
| `` C `` | Enviar alteração usando um editor Git | |
|
||||||
|
| `` <c-f> `` | Encontrar commit da base para consertar | Encontre o commit em que as suas mudanças atuais estão se baseando, para alterar/consertar o commit. Isso poupa-te você de ter que olhar pelos commits da sua branch um por um para ver qual commit deve ser alterado/consertado
|
||||||
|
Veja a documentação:
|
||||||
|
<https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
|
| `` e `` | Editar | Abrir arquivo no editor externo. |
|
||||||
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` i `` | Ignore or exclude file | |
|
||||||
|
| `` r `` | Atualizar arquivos | |
|
||||||
|
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
|
| `` S `` | View stash options | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
|
| `` a `` | Stage completo | Alternar para todos os arquivos na árvore de trabalho |
|
||||||
|
| `` <enter> `` | Stage lines / Colapso diretório | Se o item selecionado for um arquivo, o foco na exibição de preparo para o estágio de cenas/linhas individuais. Se o item selecionado for um diretório, recolher/expandi-lo. |
|
||||||
|
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||||
|
| `` g `` | View upstream reset options | |
|
||||||
|
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
|
| `` ` `` | Alternar exibição de árvore de arquivo | Alternar a visualização de arquivo entre layout plano e layout de árvore. Layout plano mostra todos os caminhos de arquivo em uma única lista, layout de árvore agrupa arquivos por diretório. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
|
||||||
|
| `` f `` | Buscar | Buscar alterações do controle remoto. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Branches locais
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||||
|
| `` i `` | Show git-flow options | |
|
||||||
|
| `` <space> `` | Verificar | Checar item selecionado |
|
||||||
|
| `` n `` | Nova branch | |
|
||||||
|
| `` o `` | Create pull request | |
|
||||||
|
| `` O `` | View create pull request options | |
|
||||||
|
| `` <c-y> `` | Copiar URL do pull request para área de transferência | |
|
||||||
|
| `` c `` | Checar por nome | Checar por nome. Na caixa de entrada você pode inserir '-' para trocar para a última branch |
|
||||||
|
| `` F `` | Forçar checagem | Forçar checagem da branch selecionada. Isso irá descartar todas as mudanças no seu diretório de trabalho antes cheque a branch selecionada |
|
||||||
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
|
| `` r `` | Refazer | Refazer a branch checada na branch selecionada |
|
||||||
|
| `` M `` | Mesclar | Ver opções para mesclar o item selecionado no branch atual (mesclar regularmente, mesclar squash) |
|
||||||
|
| `` f `` | Avanço rápido | Encaminhamento rápido de branch selecionada a partir do upstream. |
|
||||||
|
| `` T `` | New tag | |
|
||||||
|
| `` s `` | Sort order | |
|
||||||
|
| `` g `` | Reset | |
|
||||||
|
| `` R `` | Rename branch | |
|
||||||
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Branches remotos
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||||
|
| `` <space> `` | Verificar | Checar a nova branch baseada na brach remota selecionada, ou a branch remota como HEAD, desanexado |
|
||||||
|
| `` n `` | Nova branch | |
|
||||||
|
| `` M `` | Mesclar | Ver opções para mesclar o item selecionado no branch atual (mesclar regularmente, mesclar squash) |
|
||||||
|
| `` r `` | Refazer | Refazer a branch checada na branch selecionada |
|
||||||
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
|
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||||
|
| `` s `` | Sort order | |
|
||||||
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Commit files
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy path to clipboard | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
|
| `` c `` | Verificar | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||||
|
| `` 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. |
|
||||||
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` e `` | Editar | Abrir arquivo no editor externo. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <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. |
|
||||||
|
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
|
| `` <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. |
|
||||||
|
| `` ` `` | Alternar exibição de árvore de arquivo | Alternar a visualização de arquivo entre layout plano e layout de árvore. Layout plano mostra todos os caminhos de arquivo em uma única lista, layout de árvore agrupa arquivos por diretório. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Commits
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
|
| `` b `` | View bisect options | |
|
||||||
|
| `` s `` | Squash | Squash o commit selecionado no commit abaixo dele. A mensagem do commit selecionado será anexada ao commit abaixo dele. |
|
||||||
|
| `` f `` | Fixup | Faça o commit selecionado no commit abaixo dele. Semelhante para o squash, mas a mensagem do commit selecionado será descartada. |
|
||||||
|
| `` r `` | Reword | Repetir a mensagem de submissão selecionada. |
|
||||||
|
| `` R `` | Republicar com o editor | |
|
||||||
|
| `` d `` | Descartar | Solte o commit selecionado. Isso irá remover o commit do branch através de uma rebase. Se o commit faz com que as alterações em commits posteriores dependem, você pode precisar resolver conflitos de merge. |
|
||||||
|
| `` e `` | Editar (iniciar rebase interativa) | Editar o commit selecionado. Use isto para iniciar uma rebase interativa a partir do commit selecionado. Quando já estiver no meio da reconstrução, isto irá marcar o commit selecionado para edição, o que significa que ao continuar com a reformulação. a rebase irá pausar no commit selecionado para permitir que você faça alterações. |
|
||||||
|
| `` 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.
|
||||||
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
|
| `` p `` | Escolher | Marque o commit selecionado para ser escolhido (quando meados da base). Isso significa que o commit será mantido ao continuar o rebase. |
|
||||||
|
| `` 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. |
|
||||||
|
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
||||||
|
| `` <c-j> `` | Mover commit um para baixo | |
|
||||||
|
| `` <c-k> `` | Mover o commit um para cima | |
|
||||||
|
| `` V `` | Colar (cherry-pick) | |
|
||||||
|
| `` 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. |
|
||||||
|
| `` A `` | Modificar | Alterar o commit com mudanças em sted. Se o commit selecionado for o commit HEAD, ele executará o `git commit --amend`. Caso contrário, o compromisso será alterado por meio de uma base de apoio. |
|
||||||
|
| `` a `` | Alterar atributo de commit | Definir/Redefinir autor de submissão ou co-autor definido. |
|
||||||
|
| `` t `` | Reverter | Crie um commit reverter para o commit selecionado, que aplica as alterações do commit selecionado em reverso. |
|
||||||
|
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
|
| `` <c-l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
|
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
|
||||||
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
|
| `` o `` | Open commit in browser | |
|
||||||
|
| `` n `` | Create new branch off of commit | |
|
||||||
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Confirmation panel
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Confirmar | |
|
||||||
|
| `` <esc> `` | Fechar/Cancelar | |
|
||||||
|
|
||||||
|
## Etiquetas
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | Verificar | Checar a tag selecionada como um HEAD, desanexado |
|
||||||
|
| `` n `` | New tag | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
|
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Menu
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Executar | |
|
||||||
|
| `` <esc> `` | Fechar | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Painel Principal (Normal)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` mouse wheel down (fn+up) `` | Scroll down | |
|
||||||
|
| `` mouse wheel up (fn+down) `` | Scroll up | |
|
||||||
|
|
||||||
|
## Painel Principal (preparação)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <left> `` | Go to previous hunk | |
|
||||||
|
| `` <right> `` | Go to next hunk | |
|
||||||
|
| `` v `` | Toggle range select | |
|
||||||
|
| `` a `` | Selecione o local | Ativa/desativa modo seleção de hunk |
|
||||||
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
|
| `` <space> `` | Etapa | Ativar/desativar seleção em staged/unstaged |
|
||||||
|
| `` d `` | Descartar | Quando a mudança não desejada for selecionada, descarte a mudança usando `git reset`. Quando a mudança em fase é selecionada, despare a mudança. |
|
||||||
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
|
||||||
|
| `` <esc> `` | Retornar ao painel de arquivos | |
|
||||||
|
| `` <tab> `` | Mudar de visão | Alternar para outra visão (staged/não processadas alterações). |
|
||||||
|
| `` E `` | Editar hunk | Editar o local selecionado no editor externo. |
|
||||||
|
| `` c `` | Commit | Submeter mudanças em staging |
|
||||||
|
| `` w `` | Commit changes without pre-commit hook | |
|
||||||
|
| `` C `` | Enviar alteração usando um editor Git | |
|
||||||
|
| `` <c-f> `` | Encontrar commit da base para consertar | Encontre o commit em que as suas mudanças atuais estão se baseando, para alterar/consertar o commit. Isso poupa-te você de ter que olhar pelos commits da sua branch um por um para ver qual commit deve ser alterado/consertado
|
||||||
|
Veja a documentação:
|
||||||
|
<https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Painel principal (mesclagem)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <space> `` | Escolha o local | |
|
||||||
|
| `` b `` | Pegar todos os pedaços | |
|
||||||
|
| `` <up> `` | Previous hunk | |
|
||||||
|
| `` <down> `` | Next hunk | |
|
||||||
|
| `` <left> `` | Previous conflict | |
|
||||||
|
| `` <right> `` | Next conflict | |
|
||||||
|
| `` z `` | Desfazer | Desfazer resolução de conflitos de última mesclagem. |
|
||||||
|
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
|
||||||
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` M `` | Abrir ferramenta de merge externa | Execute `git mergetool`. |
|
||||||
|
| `` <esc> `` | Retornar ao painel de arquivos | |
|
||||||
|
|
||||||
|
## Painel principal (patch build)
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <left> `` | Go to previous hunk | |
|
||||||
|
| `` <right> `` | Go to next hunk | |
|
||||||
|
| `` v `` | Toggle range select | |
|
||||||
|
| `` a `` | Selecione o local | Ativa/desativa modo seleção de hunk |
|
||||||
|
| `` <c-o> `` | Copy selected text to clipboard | |
|
||||||
|
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
|
||||||
|
| `` <space> `` | Alternar linhas no caminho | |
|
||||||
|
| `` <esc> `` | Exit custom patch builder | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Reflog
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
|
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
|
||||||
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
|
| `` o `` | Open commit in browser | |
|
||||||
|
| `` n `` | Create new branch off of commit | |
|
||||||
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
|
||||||
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View commits | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Remotes
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | View branches | |
|
||||||
|
| `` n `` | New remote | |
|
||||||
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
|
| `` e `` | Editar | Edit the selected remote's name or URL. |
|
||||||
|
| `` f `` | Buscar | 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
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <space> `` | Aplicar | Aplique o stash no seu diretório de trabalho. |
|
||||||
|
| `` g `` | Pop | Aplique a entrada de stash no seu diretório de trabalho e remova a entrada de stash. |
|
||||||
|
| `` d `` | Descartar | Remova a entrada do stash da lista de armazenamento. |
|
||||||
|
| `` n `` | Nova branch | Criar um novo ramo a partir da entrada de lixo selecionada. Isso funciona verificando o commit do qual a entrada de lixo foi criada, criar um novo branch a partir desse commit e, em seguida, aplicar a entrada de lixo ao novo branch como um commit adicional. |
|
||||||
|
| `` r `` | Renomear o stasj | |
|
||||||
|
| `` <enter> `` | View files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` o `` | Abrir o ficheiro de config | Abrir arquivo no aplicativo padrão. |
|
||||||
|
| `` e `` | Editar arquivo de configuração | Abrir arquivo no editor externo. |
|
||||||
|
| `` u `` | Verificar atualização | |
|
||||||
|
| `` <enter> `` | Mudar para um repositório recente | |
|
||||||
|
| `` a `` | Mostrar todos os logs da branch | |
|
||||||
|
|
||||||
|
## Sub-commits
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy commit hash to clipboard | |
|
||||||
|
| `` <space> `` | Verificar | Checkout the selected commit as a detached HEAD. |
|
||||||
|
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
|
| `` o `` | Open commit in browser | |
|
||||||
|
| `` n `` | Create new branch off of commit | |
|
||||||
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
|
||||||
|
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||||
|
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
|
||||||
|
| `` <enter> `` | View files | |
|
||||||
|
| `` w `` | View worktree options | |
|
||||||
|
| `` / `` | Search the current view by text | |
|
||||||
|
|
||||||
|
## Submodules
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | Copy submodule name to clipboard | |
|
||||||
|
| `` <enter> `` | Enter | Enter submodule. After entering the submodule, you can press `<esc>` to escape back to the parent repo. |
|
||||||
|
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||||
|
| `` u `` | Update | Update selected submodule. |
|
||||||
|
| `` n `` | New submodule | |
|
||||||
|
| `` e `` | Update submodule URL | |
|
||||||
|
| `` 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. |
|
||||||
|
| `` b `` | View bulk submodule options | |
|
||||||
|
| `` / `` | Filter the current view by text | |
|
||||||
|
|
||||||
|
## Sumário do commit
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <enter> `` | Confirmar | |
|
||||||
|
| `` <esc> `` | Fechar | |
|
||||||
|
|
||||||
|
## Worktrees
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | Abrir no 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 | |
|
||||||
@@ -14,16 +14,18 @@ _Связки клавиш_
|
|||||||
| `` @ `` | Открыть меню журнала команд | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | Открыть меню журнала команд | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | Отправить изменения | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | Отправить изменения | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
| `` p `` | Получить и слить изменения | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` p `` | Получить и слить изменения | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | Увеличить размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | Увеличить размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | Выполнить пользовательскую команду | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | Просмотреть пользовательские параметры патча | |
|
| `` <c-p> `` | Просмотреть пользовательские параметры патча | |
|
||||||
| `` m `` | Просмотреть параметры слияния/перебазирования | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | Просмотреть параметры слияния/перебазирования | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
|
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
|
||||||
| `` _ `` | Предыдущий режим экрана | |
|
| `` _ `` | Предыдущий режим экрана | |
|
||||||
| `` ? `` | Открыть меню | |
|
| `` ? `` | Открыть меню | |
|
||||||
| `` <c-s> `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | Просмотреть параметры фильтрации по пути | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | Открыть меню сравнении | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | Выйти | |
|
| `` q `` | Выйти | |
|
||||||
@@ -78,6 +80,7 @@ _Связки клавиш_
|
|||||||
| `` c `` | Сохранить изменения | Commit staged changes. |
|
| `` c `` | Сохранить изменения | Commit staged changes. |
|
||||||
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
|
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
|
||||||
| `` C `` | Сохранить изменения с помощью редактора git | |
|
| `` 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> |
|
||||||
| `` / `` | Найти | |
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Главная панель (Обычный)
|
## Главная панель (Обычный)
|
||||||
@@ -122,7 +125,7 @@ _Связки клавиш_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Открыть коммит в браузере | |
|
| `` o `` | Открыть коммит в браузере | |
|
||||||
@@ -139,11 +142,11 @@ _Связки клавиш_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
|
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
|
||||||
| `` b `` | Просмотреть параметры бинарного поиска | |
|
| `` b `` | Просмотреть параметры бинарного поиска | |
|
||||||
| `` s `` | Объединить коммиты (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | Объединить коммиты (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | Объединить несколько коммитов в один отбросив сообщение коммита (Fixup) | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | Объединить несколько коммитов в один отбросив сообщение коммита (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | Перефразировать коммит | Reword the selected commit's message. |
|
| `` r `` | Перефразировать коммит | Reword the selected commit's message. |
|
||||||
| `` R `` | Переписать коммит с помощью редактора | |
|
| `` R `` | Переписать коммит с помощью редактора | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
@@ -151,7 +154,7 @@ _Связки клавиш_
|
|||||||
| `` 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.
|
| `` 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.
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
| `` p `` | Pick | Выбрать коммит (в середине перебазирования) |
|
| `` p `` | Pick | Выбрать коммит (в середине перебазирования) |
|
||||||
| `` F `` | Create fixup commit | Создать fixup коммит для этого коммита |
|
| `` F `` | Создать fixup коммит | Создать fixup коммит для этого коммита |
|
||||||
| `` S `` | Apply fixup commits | Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение) |
|
| `` S `` | Apply fixup commits | Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение) |
|
||||||
| `` <c-j> `` | Переместить коммит вниз на один | |
|
| `` <c-j> `` | Переместить коммит вниз на один | |
|
||||||
| `` <c-k> `` | Переместить коммит вверх на один | |
|
| `` <c-k> `` | Переместить коммит вверх на один | |
|
||||||
@@ -188,13 +191,14 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` F `` | Принудительное переключение | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | Принудительное переключение | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||||
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | Слияние с текущей переключённой веткой | Merge selected branch into currently checked out branch. |
|
| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | Перемотать эту ветку вперёд из её upstream-ветки | Fast-forward selected branch from its upstream. |
|
| `` f `` | Перемотать эту ветку вперёд из её upstream-ветки | Fast-forward selected branch from its upstream. |
|
||||||
| `` T `` | Создать тег | |
|
| `` T `` | Создать тег | |
|
||||||
| `` s `` | Порядок сортировки | |
|
| `` s `` | Порядок сортировки | |
|
||||||
| `` g `` | Просмотреть параметры сброса | |
|
| `` g `` | Просмотреть параметры сброса | |
|
||||||
| `` R `` | Переименовать ветку | |
|
| `` R `` | Переименовать ветку | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Просмотреть коммиты | |
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -218,7 +222,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
|
||||||
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | Переключить | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | Открыть коммит в браузере | |
|
| `` o `` | Открыть коммит в браузере | |
|
||||||
@@ -257,6 +261,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
|
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
|
||||||
|
| `` y `` | Copy to clipboard | |
|
||||||
| `` c `` | Переключить | Переключить файл |
|
| `` c `` | Переключить | Переключить файл |
|
||||||
| `` d `` | Remove | Отменить изменения коммита в этом файле |
|
| `` d `` | Remove | Отменить изменения коммита в этом файле |
|
||||||
| `` o `` | Открыть файл | Open file in default application. |
|
| `` o `` | Открыть файл | Open file in default application. |
|
||||||
@@ -266,6 +271,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` a `` | Переключить все файлы, включённые в патч | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` a `` | Переключить все файлы, включённые в патч | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Найти | |
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
@@ -282,11 +289,13 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | Переключить | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | Переключить | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | Создать тег | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | Создать тег | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||||
| `` P `` | Отправить тег | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | Отправить тег | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Просмотреть коммиты | |
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -296,14 +305,15 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
|
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
|
||||||
| `` <space> `` | Переключить | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | Переключить | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | Новая ветка | |
|
| `` n `` | Новая ветка | |
|
||||||
| `` M `` | Слияние с текущей переключённой веткой | Merge selected branch into currently checked out branch. |
|
| `` M `` | Слияние с текущей переключённой веткой | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | Установить как upstream-ветку переключённую ветку |
|
| `` u `` | Set as upstream | Установить как upstream-ветку переключённую ветку |
|
||||||
| `` s `` | Порядок сортировки | |
|
| `` s `` | Порядок сортировки | |
|
||||||
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` <enter> `` | Просмотреть коммиты | |
|
| `` <enter> `` | Просмотреть коммиты | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | View worktree options | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | Filter the current view by text | |
|
||||||
@@ -347,6 +357,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||||
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
|
||||||
| `` f `` | Получить изменения | Fetch changes from remote. |
|
| `` f `` | Получить изменения | Fetch changes from remote. |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | Найти | |
|
| `` / `` | Найти | |
|
||||||
|
|
||||||
## Хранилище
|
## Хранилище
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
|
|
||||||
# Lazygit 按键绑定
|
# Lazygit 按键绑定
|
||||||
|
|
||||||
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
_图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
||||||
|
|
||||||
## 全局键绑定
|
## 全局键绑定
|
||||||
|
|
||||||
@@ -11,26 +11,28 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` <c-r> `` | 切换到最近的仓库 | |
|
| `` <c-r> `` | 切换到最近的仓库 | |
|
||||||
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
|
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
|
||||||
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
|
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
|
||||||
| `` @ `` | 打开命令日志菜单 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 |
|
||||||
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,你可以在弹窗中配置上游分支。 |
|
||||||
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游未配置,你可以在弹窗中配置上游分支。 |
|
||||||
| `` } `` | 扩大差异视图中显示的上下文范围 | Increase the amount of the context shown around changes in the diff view. |
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` { `` | 缩小差异视图中显示的上下文范围 | Decrease the amount of the context shown around changes in the diff view. |
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` : `` | 执行自定义命令 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
| `` } `` | 扩大差异视图中显示的上下文范围 | 增加diff视图中围绕更改显示的上下文数量 |
|
||||||
|
| `` { `` | 缩小差异视图中显示的上下文范围 | 减少diff视图中围绕更改显示的上下文数量 |
|
||||||
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | 查看自定义补丁选项 | |
|
| `` <c-p> `` | 查看自定义补丁选项 | |
|
||||||
| `` m `` | 查看 合并/变基 选项 | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | 查看 合并/变基 选项 | 查看当前合并或变基的中止、继续、跳过选项 |
|
||||||
| `` 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`. |
|
| `` R `` | 刷新 | 刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch` |
|
||||||
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||||
| `` _ `` | 上一屏模式 | |
|
| `` _ `` | 上一屏模式 | |
|
||||||
| `` ? `` | 打开菜单 | |
|
| `` ? `` | 打开菜单 | |
|
||||||
| `` <c-s> `` | 查看按路径过滤选项 | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 |
|
||||||
| `` 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. |
|
| `` W `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 |
|
||||||
| `` <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. |
|
| `` <c-e> `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 |
|
||||||
| `` q `` | 退出 | |
|
| `` q `` | 退出 | |
|
||||||
| `` <esc> `` | 取消 | |
|
| `` <esc> `` | 取消 | |
|
||||||
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | Toggle whether or not whitespace changes are shown in the diff view. |
|
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | 切换是否在diff视图中显示空白更改 |
|
||||||
| `` 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. |
|
| `` z `` | (通过 reflog)撤销「实验功能」 | Reflog将用于确定运行哪个git命令来撤消最后一个git命令。这并不包括对工作树的更改,只考虑提交。 |
|
||||||
| `` <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. |
|
| `` <c-z> `` | (通过 reflog)重做「实验功能」 | Reflog将用于确定运行哪个git命令来重做上一个git命令。这并不包括对工作树的更改,只考虑提交。 |
|
||||||
|
|
||||||
## 列表面板导航
|
## 列表面板导航
|
||||||
|
|
||||||
@@ -41,8 +43,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| `` < `` | 滚动到顶部 | |
|
| `` < `` | 滚动到顶部 | |
|
||||||
| `` > `` | 滚动到底部 | |
|
| `` > `` | 滚动到底部 | |
|
||||||
| `` v `` | 切换拖动选择 | |
|
| `` v `` | 切换拖动选择 | |
|
||||||
| `` <s-down> `` | Range select down | |
|
| `` <s-down> `` | 向下扩展选择范围 | |
|
||||||
| `` <s-up> `` | Range select up | |
|
| `` <s-up> `` | 向上扩展选择范围 | |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
| `` H `` | 向左滚动 | |
|
| `` H `` | 向左滚动 | |
|
||||||
| `` L `` | 向右滚动 | |
|
| `` L `` | 向右滚动 | |
|
||||||
@@ -53,28 +55,18 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||||
| `` o `` | 在浏览器中打开提交 | |
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
| `` n `` | 从提交创建新分支 | |
|
| `` n `` | 从提交创建新分支 | |
|
||||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||||
| `` 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 `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交 | |
|
| `` <enter> `` | 查看提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | 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 | |
|
|
||||||
|
|
||||||
## 分支页面
|
## 分支页面
|
||||||
|
|
||||||
@@ -82,41 +74,42 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||||
| `` i `` | 显示 git-flow 选项 | |
|
| `` i `` | 显示 git-flow 选项 | |
|
||||||
| `` <space> `` | 检出 | Checkout selected item. |
|
| `` <space> `` | 检出 | 检出选中的项目 |
|
||||||
| `` n `` | 新分支 | |
|
| `` n `` | 新分支 | |
|
||||||
| `` o `` | 创建抓取请求 | |
|
| `` o `` | 创建拉取请求 | |
|
||||||
| `` O `` | 创建抓取请求选项 | |
|
| `` O `` | 创建拉取请求选项 | |
|
||||||
| `` <c-y> `` | 将抓取请求 URL 复制到剪贴板 | |
|
| `` <c-y> `` | 将拉取请求 URL 复制到剪贴板 | |
|
||||||
| `` c `` | 按名称检出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
| `` c `` | 按名称检出 | 按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。 |
|
||||||
| `` F `` | 强制检出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | 强制检出 | 强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。 |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | 删除 | 查看本地/远程分支的删除选项 |
|
||||||
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||||
| `` f `` | 从上游快进此分支 | Fast-forward selected branch from its upstream. |
|
| `` f `` | 从上游快进此分支 | 将当前分支直接移动到远程追踪分支的最新提交 |
|
||||||
| `` T `` | 创建标签 | |
|
| `` T `` | 创建标签 | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | 排序 | |
|
||||||
| `` g `` | 查看重置选项 | |
|
| `` g `` | 查看重置选项 | |
|
||||||
| `` R `` | 重命名分支 | |
|
| `` R `` | 重命名分支 | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 |
|
||||||
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交 | |
|
| `` <enter> `` | 查看提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||||
| `` o `` | 在浏览器中打开提交 | |
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
| `` n `` | 从提交创建新分支 | |
|
| `` n `` | 从提交创建新分支 | |
|
||||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||||
| `` 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 `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交的文件 | |
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 子模块
|
## 子模块
|
||||||
@@ -124,104 +117,119 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
|
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
|
||||||
| `` <enter> `` | Enter | 输入子模块 |
|
| `` <enter> `` | 进入 | 输入子模块 |
|
||||||
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
| `` d `` | 删除 | 删除选定的子模块及其相应的目录 |
|
||||||
| `` u `` | Update | 更新子模块 |
|
| `` u `` | 更新 | 更新子模块 |
|
||||||
| `` n `` | 添加新的子模块 | |
|
| `` n `` | 添加新的子模块 | |
|
||||||
| `` e `` | 更新子模块 URL | |
|
| `` e `` | 更新子模块 URL | |
|
||||||
| `` i `` | Initialize | 初始化子模块 |
|
| `` i `` | 初始化 | 初始化子模块 |
|
||||||
| `` b `` | 查看批量子模块选项 | |
|
| `` b `` | 查看批量子模块选项 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
|
## 工作区
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | 新建工作树 | |
|
||||||
|
| `` <space> `` | 切换 | 切换到选中的工作树 |
|
||||||
|
| `` o `` | 在编辑器中编写 | |
|
||||||
|
| `` d `` | 删除 | 删除选定的工作树。这将删除工作树的目录以及 .git 目录中有关工作树的元数据。 |
|
||||||
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||||
| `` b `` | 查看二分查找选项 | |
|
| `` b `` | 查看二分查找选项 | |
|
||||||
| `` s `` | 压缩 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | 压缩(Squash) | 将已选提交压缩到该提交之下。这些选定的提交的消息会附加到该提交的消息之下。 |
|
||||||
| `` f `` | 修正(fixup) | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | 修正(fixup) | 将选定的提交合并到其下面的提交中。与压缩类似,但所选提交的消息将被丢弃。 |
|
||||||
| `` r `` | 改写提交 | Reword the selected commit's message. |
|
| `` r `` | 改写提交 | 重写所选提交的消息。 |
|
||||||
| `` R `` | 使用编辑器重命名提交 | |
|
| `` R `` | 使用编辑器重命名提交 | |
|
||||||
| `` 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. |
|
| `` d `` | 删除提交 | 删除选中的提交。这将通过变基从分支中删除该提交,如果该提交修改的内容依赖于后续的提交,则需要解决合并冲突。 |
|
||||||
| `` e `` | Edit (start interactive rebase) | 编辑提交 |
|
| `` e `` | 编辑(开始交互式变基) | 编辑提交 |
|
||||||
| `` 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.
|
| `` i `` | 开始交互式变基 | 为分支上的提交启动交互式变基。这将包括从 HEAD 提交到第一个合并提交或主分支提交的所有提交。
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
如果您想从所选提交启动交互式变基,请按 `e`。 |
|
||||||
| `` p `` | Pick | 选择提交(变基过程中) |
|
| `` p `` | 拣选(Pick) | 选择提交(变基过程中) |
|
||||||
| `` F `` | Create fixup commit | 创建修正提交 |
|
| `` F `` | 为此提交创建修正 | 创建修正提交 |
|
||||||
| `` S `` | Apply fixup commits | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
|
| `` S `` | 应用该修复提交 | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
|
||||||
| `` <c-j> `` | 下移提交 | |
|
| `` <c-j> `` | 下移提交 | |
|
||||||
| `` <c-k> `` | 上移提交 | |
|
| `` <c-k> `` | 上移提交 | |
|
||||||
| `` V `` | 粘贴提交(拣选) | |
|
| `` V `` | 粘贴提交(拣选) | |
|
||||||
| `` 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. |
|
| `` B `` | 标记一个主提交用于变基 | 选择下一次变基的主提交。当您变基到一个分支时,只有高于主提交的提交才会被引入。这使用“git rebase --onto”命令。 |
|
||||||
| `` A `` | Amend | 用已暂存的更改来修补提交 |
|
| `` A `` | 修补(Amend) | 用已暂存的变更来修补提交 |
|
||||||
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
| `` a `` | 修补提交属性 | 设置或重置提交的作者,或添加其他作者。 |
|
||||||
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
| `` t `` | 撤销(Revert) | 为所选提交创建还原提交,这会反向应用所选提交的更改。 |
|
||||||
| `` T `` | 标签提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
| `` T `` | 标签提交 | 创建一个新标签指向所选提交。你可以在弹窗中输入标签名称和描述(可选)。 |
|
||||||
| `` <c-l> `` | 打开日志菜单 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
| `` <c-l> `` | 打开日志菜单 | 查看提交日志的选项,例如更改排序顺序、隐藏 git graph、显示整个 git graph。 |
|
||||||
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||||
| `` o `` | 在浏览器中打开提交 | |
|
| `` o `` | 在浏览器中打开提交 | |
|
||||||
| `` n `` | 从提交创建新分支 | |
|
| `` n `` | 从提交创建新分支 | |
|
||||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||||
| `` 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 `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交的文件 | |
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 提交文件
|
## 提交信息
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
|
||||||
| `` c `` | 检出 | 检出文件 |
|
|
||||||
| `` d `` | Remove | 放弃对此文件的提交更改 |
|
|
||||||
| `` o `` | 打开文件 | Open file in default application. |
|
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
|
||||||
| `` <space> `` | 补丁中包含的切换文件 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
|
||||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
|
||||||
| `` <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. |
|
|
||||||
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
|
||||||
| `` / `` | 开始搜索 | |
|
|
||||||
|
|
||||||
## 提交讯息
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | 确认 | |
|
| `` <enter> `` | 确认 | |
|
||||||
| `` <esc> `` | 关闭 | |
|
| `` <esc> `` | 关闭 | |
|
||||||
|
|
||||||
|
## 提交文件
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||||
|
| `` y `` | 复制到剪贴板 | |
|
||||||
|
| `` c `` | 检出 | 检出文件 |
|
||||||
|
| `` d `` | 删除 | 放弃对此文件的提交变更 |
|
||||||
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
|
| `` e `` | 编辑 | 使用外部编辑器打开文件 |
|
||||||
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
|
| `` <space> `` | 补丁中包含的切换文件 | 切换文件是否包含在自定义补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
|
||||||
|
| `` a `` | 操作所有文件 | 添加或删除所有提交中的文件到自定义的补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
|
||||||
|
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | 如果已选择一个文件,则Enter进入该文件,以便您可以向自定义补丁添加/删除单独的行。如果选择了目录,则切换目录。 |
|
||||||
|
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 文件
|
## 文件
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||||
| `` <space> `` | 切换暂存状态 | Toggle staged for selected file. |
|
| `` <space> `` | 切换暂存状态 | 为选定的文件切换暂存状态 |
|
||||||
| `` <c-b> `` | Filter files by status | |
|
| `` <c-b> `` | 通过状态过滤文件 | |
|
||||||
| `` y `` | Copy to clipboard | |
|
| `` y `` | 复制到剪贴板 | |
|
||||||
| `` c `` | 提交更改 | Commit staged changes. |
|
| `` c `` | 提交变更 | 提交暂存文件 |
|
||||||
| `` w `` | 提交更改而无需预先提交钩子 | |
|
| `` w `` | 提交变更而无需预先提交钩子 | |
|
||||||
| `` A `` | 修补最后一次提交 | |
|
| `` A `` | 修补最后一次提交 | |
|
||||||
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
|
||||||
| `` <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> |
|
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
| `` e `` | 编辑 | 使用外部编辑器打开文件 |
|
||||||
| `` o `` | 打开文件 | Open file in default application. |
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
| `` i `` | 忽略文件 | |
|
| `` i `` | 忽略文件 | |
|
||||||
| `` r `` | 刷新文件 | |
|
| `` r `` | 刷新文件 | |
|
||||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
| `` s `` | 贮藏 | 贮藏所有变更.若要使用其他贮藏变体,请使用查看贮藏选项快捷键 |
|
||||||
| `` S `` | 查看贮藏选项 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
| `` S `` | 查看贮藏选项 | 查看贮藏选项(例如:贮藏所有、贮藏已暂存变更、贮藏未暂存变更) |
|
||||||
| `` a `` | 切换所有文件的暂存状态 | Toggle staged/unstaged for all files in working tree. |
|
| `` a `` | 切换所有文件的暂存状态 | 切换工作区中所有文件的已暂存/未暂存状态 |
|
||||||
| `` <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. |
|
| `` <enter> `` | 暂存单个 块/行 用于文件, 或 折叠/展开 目录 | 如果选中的是一个文件,则会进入到暂存视图,以便可以暂存单个代码块/行。如果选中的是一个目录,则会折叠/展开这个目录 |
|
||||||
| `` d `` | 查看'放弃更改'选项 | View options for discarding changes to the selected file. |
|
| `` d `` | 查看'放弃变更'选项 | 查看选中文件的放弃变更选项 |
|
||||||
| `` g `` | 查看上游重置选项 | |
|
| `` g `` | 查看上游重置选项 | |
|
||||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
| `` D `` | 重置 | 查看工作树的重置选项(例如:清除工作树)。 |
|
||||||
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
||||||
| `` f `` | 抓取 | Fetch changes from remote. |
|
| `` f `` | 抓取 | 从远程获取变更 |
|
||||||
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 构建补丁中
|
## 构建补丁中
|
||||||
@@ -231,10 +239,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <left> `` | 选择上一个区块 | |
|
| `` <left> `` | 选择上一个区块 | |
|
||||||
| `` <right> `` | 选择下一个区块 | |
|
| `` <right> `` | 选择下一个区块 | |
|
||||||
| `` v `` | 切换拖动选择 | |
|
| `` v `` | 切换拖动选择 | |
|
||||||
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||||
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||||
| `` o `` | 打开文件 | Open file in default application. |
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
| `` e `` | 编辑文件 | Open file in external editor. |
|
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||||
| `` <space> `` | 添加/移除 行到补丁 | |
|
| `` <space> `` | 添加/移除 行到补丁 | |
|
||||||
| `` <esc> `` | 退出逐行模式 | |
|
| `` <esc> `` | 退出逐行模式 | |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
@@ -243,14 +251,16 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | 检出 | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
| `` n `` | 创建标签 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` <space> `` | 检出 | 检出选择的标签作为分离的HEAD |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。 |
|
||||||
| `` P `` | 推送标签 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` d `` | 删除 | 查看本地/远程标签的删除选项 |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` P `` | 推送标签 | 推送选择的标签到远端。你将在弹窗中选择一个远端。 |
|
||||||
|
| `` g `` | 重置 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||||
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交 | |
|
| `` <enter> `` | 查看提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 正在合并
|
## 正在合并
|
||||||
|
|
||||||
@@ -262,10 +272,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <down> `` | 选择底部块 | |
|
| `` <down> `` | 选择底部块 | |
|
||||||
| `` <left> `` | 选择上一个冲突 | |
|
| `` <left> `` | 选择上一个冲突 | |
|
||||||
| `` <right> `` | 选择下一个冲突 | |
|
| `` <right> `` | 选择下一个冲突 | |
|
||||||
| `` z `` | 撤销 | Undo last merge conflict resolution. |
|
| `` z `` | 撤销 | 撤消上次合并冲突解决 |
|
||||||
| `` e `` | 编辑文件 | Open file in external editor. |
|
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||||
| `` o `` | 打开文件 | Open file in default application. |
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
||||||
| `` <esc> `` | 返回文件面板 | |
|
| `` <esc> `` | 返回文件面板 | |
|
||||||
|
|
||||||
## 正在暂存
|
## 正在暂存
|
||||||
@@ -275,18 +285,19 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <left> `` | 选择上一个区块 | |
|
| `` <left> `` | 选择上一个区块 | |
|
||||||
| `` <right> `` | 选择下一个区块 | |
|
| `` <right> `` | 选择下一个区块 | |
|
||||||
| `` v `` | 切换拖动选择 | |
|
| `` v `` | 切换拖动选择 | |
|
||||||
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||||
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||||
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
|
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
|
||||||
| `` d `` | 取消变更 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 |
|
||||||
| `` o `` | 打开文件 | Open file in default application. |
|
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||||
| `` e `` | 编辑文件 | Open file in external editor. |
|
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||||
| `` <esc> `` | 返回文件面板 | |
|
| `` <esc> `` | 返回文件面板 | |
|
||||||
| `` <tab> `` | 切换到其他面板 | Switch to other view (staged/unstaged changes). |
|
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
|
||||||
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
| `` E `` | 编辑代码块 | 在外部编辑器中编辑选中的代码块 |
|
||||||
| `` c `` | 提交更改 | Commit staged changes. |
|
| `` c `` | 提交变更 | 提交暂存文件 |
|
||||||
| `` w `` | 提交更改而无需预先提交钩子 | |
|
| `` w `` | 提交变更而无需预先提交钩子 | |
|
||||||
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
|
||||||
|
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||||
| `` / `` | 开始搜索 | |
|
| `` / `` | 开始搜索 | |
|
||||||
|
|
||||||
## 正常
|
## 正常
|
||||||
@@ -300,8 +311,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` o `` | 打开配置文件 | Open file in default application. |
|
| `` o `` | 打开配置文件 | 使用默认程序打开该文件 |
|
||||||
| `` e `` | 编辑配置文件 | Open file in external editor. |
|
| `` e `` | 编辑配置文件 | 使用外部编辑器打开文件 |
|
||||||
| `` u `` | 检查更新 | |
|
| `` u `` | 检查更新 | |
|
||||||
| `` <enter> `` | 切换到最近的仓库 | |
|
| `` <enter> `` | 切换到最近的仓库 | |
|
||||||
| `` a `` | 显示所有分支的日志 | |
|
| `` a `` | 显示所有分支的日志 | |
|
||||||
@@ -319,45 +330,46 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | 执行 | |
|
| `` <enter> `` | 执行 | |
|
||||||
| `` <esc> `` | 关闭 | |
|
| `` <esc> `` | 关闭 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 贮藏
|
## 贮藏
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | 应用 | Apply the stash entry to your working directory. |
|
| `` <space> `` | 应用 | 将贮藏项应用到您的工作目录。 |
|
||||||
| `` g `` | 应用并删除 | Apply the stash entry to your working directory and remove the stash entry. |
|
| `` g `` | 应用并删除 | 将存储项应用到工作目录并删除存储项。 |
|
||||||
| `` d `` | 删除 | Remove the stash entry from the stash list. |
|
| `` d `` | 删除 | 从贮藏列表中删除该贮藏项 |
|
||||||
| `` 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. |
|
| `` n `` | 新分支 | 从选定的贮藏项创建一个新分支。这是通过 git 检查创建贮藏项的提交,从该提交创建一个新分支,然后将贮藏项作为附加提交应用到新分支来实现的。 |
|
||||||
| `` r `` | Rename stash | |
|
| `` r `` | 重命名贮藏 | |
|
||||||
| `` <enter> `` | 查看提交的文件 | |
|
| `` <enter> `` | 查看提交的文件 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 远程分支
|
## 远程分支
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||||
| `` <space> `` | 检出 | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | 检出 | 基于当前选中的远程分支检出一个新的本地分支,或者将远程分支作分离的HEAD。 |
|
||||||
| `` n `` | 新分支 | |
|
| `` n `` | 新分支 | |
|
||||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||||
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | 删除 | 从远程删除远程分支。 |
|
||||||
| `` u `` | Set as upstream | 设置为检出分支的上游 |
|
| `` u `` | 设置为上游 | 设置为检出分支的上游 |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | 排序 | |
|
||||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||||
|
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||||
| `` <enter> `` | 查看提交 | |
|
| `` <enter> `` | 查看提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 查看工作区选项 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|
||||||
## 远程页面
|
## 远程页面
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | View branches | |
|
| `` <enter> `` | 查看分支 | |
|
||||||
| `` n `` | 添加新的远程仓库 | |
|
| `` n `` | 添加新的远程仓库 | |
|
||||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
| `` d `` | 删除 | 删除选中的远程。从远程跟踪远程分支的任何本地分支都不会受到影响。 |
|
||||||
| `` e `` | Edit | 编辑远程仓库 |
|
| `` e `` | 编辑 | 编辑远程仓库 |
|
||||||
| `` f `` | 抓取 | 抓取远程仓库 |
|
| `` f `` | 抓取 | 抓取远程仓库 |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 通过文本过滤当前视图 | |
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
|||||||
|
|
||||||
# Lazygit 鍵盤快捷鍵
|
# Lazygit 鍵盤快捷鍵
|
||||||
|
|
||||||
_說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
_說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
||||||
|
|
||||||
## 全局快捷鍵
|
## 全域快捷鍵
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
@@ -12,27 +12,29 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
| `` <pgup> (fn+up/shift+k) `` | 向上捲動主面板 | |
|
| `` <pgup> (fn+up/shift+k) `` | 向上捲動主面板 | |
|
||||||
| `` <pgdown> (fn+down/shift+j) `` | 向下捲動主面板 | |
|
| `` <pgdown> (fn+down/shift+j) `` | 向下捲動主面板 | |
|
||||||
| `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
| `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||||
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` P `` | 推送 | 推送到遠端。如果沒有設定遠端,會開啟設定視窗。 |
|
||||||
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
| `` p `` | 拉取 | 從遠端同步當前分支。如果沒有設定遠端,會開啟設定視窗。 |
|
||||||
|
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
|
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||||
| `` } `` | 增加差異檢視中顯示變更周圍上下文的大小 | Increase the amount of the context shown around changes in the diff view. |
|
| `` } `` | 增加差異檢視中顯示變更周圍上下文的大小 | Increase the amount of the context shown around changes in the diff view. |
|
||||||
| `` { `` | 減小差異檢視中顯示變更周圍上下文的大小 | Decrease the amount of the context shown around changes in the diff view. |
|
| `` { `` | 減小差異檢視中顯示變更周圍上下文的大小 | Decrease the amount of the context shown around changes in the diff view. |
|
||||||
| `` : `` | 執行自訂命令 | Bring up a prompt where you can enter a shell command to execute. Not to be confused with pre-configured custom commands. |
|
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||||
| `` <c-p> `` | 檢視自訂補丁選項 | |
|
| `` <c-p> `` | 檢視自訂補丁選項 | |
|
||||||
| `` m `` | 查看合併/變基選項 | View options to abort/continue/skip the current merge/rebase. |
|
| `` m `` | 查看合併/變基選項 | View options to abort/continue/skip the current merge/rebase. |
|
||||||
| `` 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`. |
|
| `` 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`. |
|
||||||
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
|
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
|
||||||
| `` _ `` | 上一個螢幕模式 | |
|
| `` _ `` | 上一個螢幕模式 | |
|
||||||
| `` ? `` | 開啟選單 | |
|
| `` ? `` | 開啟選單 | |
|
||||||
| `` <c-s> `` | 檢視篩選路徑選項 | View options for filtering the commit log by a file path, so that only commits relating to that path are shown. |
|
| `` <c-s> `` | 檢視篩選路徑選項 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||||
| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
| `` W `` | 開啟差異比較選單 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` q `` | 結束 | |
|
| `` q `` | 結束 | |
|
||||||
| `` <esc> `` | 取消 | |
|
| `` <esc> `` | 取消 | |
|
||||||
| `` <c-w> `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view. |
|
| `` <c-w> `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||||
| `` z `` | 復原 | 將使用 reflog 確定要運行哪個 git 命令以復原上一個 git 命令。這不包括工作區的更改;只考慮提交。 |
|
| `` z `` | 復原 | 將使用 reflog 確任 git 指令以復原。這不包括工作區更改;只考慮提交。 |
|
||||||
| `` <c-z> `` | 取消復原 | 將使用 reflog 確定要運行哪個 git 命令以重作上一個 git 命令。這不包括工作區的更改;只考慮提交。 |
|
| `` <c-z> `` | 取消復原 | 將使用 reflog 確任 git 指令以重作。這不包括工作區更改;只考慮提交。 |
|
||||||
|
|
||||||
## 列表面板導航
|
## 移動
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
@@ -43,83 +45,12 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
| `` v `` | 切換拖曳選擇 | |
|
| `` v `` | 切換拖曳選擇 | |
|
||||||
| `` <s-down> `` | Range select down | |
|
| `` <s-down> `` | Range select down | |
|
||||||
| `` <s-up> `` | Range select up | |
|
| `` <s-up> `` | Range select up | |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` / `` | 搜尋 | |
|
||||||
| `` H `` | 向左捲動 | |
|
| `` H `` | 向左捲動 | |
|
||||||
| `` L `` | 向右捲動 | |
|
| `` L `` | 向右捲動 | |
|
||||||
| `` ] `` | 下一個索引標籤 | |
|
| `` ] `` | 下一個索引標籤 | |
|
||||||
| `` [ `` | 上一個索引標籤 | |
|
| `` [ `` | 上一個索引標籤 | |
|
||||||
|
|
||||||
## Reflog
|
|
||||||
|
|
||||||
| Key | Action | Info |
|
|
||||||
|-----|--------|-------------|
|
|
||||||
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
|
|
||||||
| `` <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 `` | 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 | |
|
|
||||||
|
|
||||||
## 主視窗 (一般)
|
|
||||||
|
|
||||||
| 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 編輯器提交變更 | |
|
|
||||||
| `` / `` | 開始搜尋 | |
|
|
||||||
|
|
||||||
## 主面板 (補丁生成)
|
## 主面板 (補丁生成)
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
@@ -129,11 +60,56 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
| `` v `` | 切換拖曳選擇 | |
|
| `` v `` | 切換拖曳選擇 | |
|
||||||
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
|
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
|
||||||
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
|
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
|
||||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
| `` e `` | 編輯檔案 | Open file in external editor. |
|
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||||
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
|
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
|
||||||
| `` <esc> `` | 退出自訂補丁建立器 | |
|
| `` <esc> `` | 退出自訂補丁建立器 | |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
|
## 主面板(一般)
|
||||||
|
|
||||||
|
| 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 `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||||
|
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
|
| `` M `` | 開啟外部合併工具 | 執行 `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 `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
|
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||||
|
| `` <esc> `` | 返回檔案面板 | |
|
||||||
|
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | Switch to other view (staged/unstaged changes). |
|
||||||
|
| `` E `` | 編輯程式碼塊 | Edit selected hunk in external editor. |
|
||||||
|
| `` c `` | 提交變更 | 提交暫存區變更 |
|
||||||
|
| `` 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> |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 功能表
|
## 功能表
|
||||||
|
|
||||||
@@ -141,13 +117,13 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <enter> `` | 執行 | |
|
| `` <enter> `` | 執行 | |
|
||||||
| `` <esc> `` | 關閉 | |
|
| `` <esc> `` | 關閉 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
|
||||||
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
||||||
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||||
| `` o `` | 在瀏覽器中開啟提交 | |
|
| `` o `` | 在瀏覽器中開啟提交 | |
|
||||||
@@ -155,10 +131,10 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` 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 `` | 複製提交 (揀選) | 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-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <enter> `` | 檢視所選項目的檔案 | |
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 子模組
|
## 子模組
|
||||||
|
|
||||||
@@ -172,33 +148,43 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
| `` e `` | 更新子模組 URL | |
|
| `` e `` | 更新子模組 URL | |
|
||||||
| `` i `` | Initialize | 初始化子模組 |
|
| `` i `` | Initialize | 初始化子模組 |
|
||||||
| `` b `` | 查看批量子模組選項 | |
|
| `` b `` | 查看批量子模組選項 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
|
## 工作目錄
|
||||||
|
|
||||||
|
| Key | Action | Info |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `` n `` | New worktree | |
|
||||||
|
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||||
|
| `` o `` | 在編輯器中開啟 | |
|
||||||
|
| `` 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. |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
|
||||||
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||||
| `` b `` | 查看二分選項 | |
|
| `` b `` | 查看二分選項 | |
|
||||||
| `` s `` | 壓縮 (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
| `` s `` | 壓縮 (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||||
| `` f `` | 修復 (Fixup) | Meld the selected commit into the commit below it. Similar to fixup, but the selected commit's message will be discarded. |
|
| `` f `` | 修復 (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||||
| `` r `` | 改寫提交 | Reword the selected commit's message. |
|
| `` r `` | 改寫提交 | 改寫選中的提交訊息 |
|
||||||
| `` R `` | 使用編輯器改寫提交 | |
|
| `` R `` | 使用編輯器改寫提交 | |
|
||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` e `` | Edit (start interactive rebase) | 編輯提交 |
|
| `` e `` | 編輯(開始互動變基) | 編輯提交 |
|
||||||
| `` 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.
|
| `` i `` | 開始互動變基 | 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.
|
||||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||||
| `` p `` | Pick | 挑選提交 (於變基過程中) |
|
| `` p `` | 挑選 | 挑選提交 (於變基過程中) |
|
||||||
| `` F `` | Create fixup commit | 為此提交建立修復提交 |
|
| `` F `` | 建立修復提交 | 為此提交建立修復提交 |
|
||||||
| `` S `` | Apply fixup commits | 壓縮上方所有的“fixup!”提交 (自動壓縮) |
|
| `` S `` | 壓縮上方所有「fixup」提交(自動壓縮) | 是否壓縮上方 {{.commit}} 所有「fixup」提交? |
|
||||||
| `` <c-j> `` | 向下移動提交 | |
|
| `` <c-j> `` | 向下移動提交 | |
|
||||||
| `` <c-k> `` | 向上移動提交 | |
|
| `` <c-k> `` | 向上移動提交 | |
|
||||||
| `` V `` | 貼上提交 (揀選) | |
|
| `` V `` | 貼上提交 (揀選) | |
|
||||||
| `` 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. |
|
| `` B `` | 為了變基已標注提交為基準提交 | 請為了下一次變基選擇一項基準提交;此將執行 `git rebase --onto`。 |
|
||||||
| `` A `` | Amend | 使用已預存的更改修正提交 |
|
| `` A `` | 修改 | 使用已預存的更改修正提交 |
|
||||||
| `` a `` | 設置/重設提交作者 | Set/Reset commit author or set co-author. |
|
| `` a `` | 設定/重設提交作者 | Set/Reset commit author or set co-author. |
|
||||||
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
| `` t `` | 還原 | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||||
| `` T `` | 打標籤到提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
| `` T `` | 打標籤到提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` <c-l> `` | 開啟記錄選單 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
| `` <c-l> `` | 開啟記錄選單 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||||
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
|
||||||
@@ -207,10 +193,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` n `` | 從提交建立新分支 | |
|
| `` n `` | 從提交建立新分支 | |
|
||||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` 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 `` | 複製提交 (揀選) | 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) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <enter> `` | 檢視所選項目的檔案 | |
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 提交摘要
|
## 提交摘要
|
||||||
|
|
||||||
@@ -224,16 +210,19 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||||
|
| `` y `` | 複製到剪貼簿 | |
|
||||||
| `` c `` | 檢出 | 檢出檔案 |
|
| `` c `` | 檢出 | 檢出檔案 |
|
||||||
| `` d `` | Remove | 捨棄此提交對此檔案的更改 |
|
| `` 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. |
|
||||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
| `` e `` | 編輯 | 使用外部編輯器開啟 |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <space> `` | 切換檔案是否包含在補丁中 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` <space> `` | 切換檔案是否包含在補丁中 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` a `` | 切換所有檔案是否包含在補丁中 | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
| `` a `` | 切換所有檔案是否包含在補丁中 | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` ` `` | 切換檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 收藏 (Stash)
|
## 收藏 (Stash)
|
||||||
|
|
||||||
@@ -245,8 +234,25 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` 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. |
|
| `` 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. |
|
||||||
| `` r `` | 重新命名收藏 | |
|
| `` r `` | 重新命名收藏 | |
|
||||||
| `` <enter> `` | 檢視所選項目的檔案 | |
|
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
|
## 日誌
|
||||||
|
|
||||||
|
| 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> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
|
| `` <enter> `` | 檢視提交 | |
|
||||||
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 本地分支
|
## 本地分支
|
||||||
|
|
||||||
@@ -254,38 +260,41 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
||||||
| `` i `` | 顯示 git-flow 選項 | |
|
| `` i `` | 顯示 git-flow 選項 | |
|
||||||
| `` <space> `` | 檢出 | Checkout selected item. |
|
| `` <space> `` | 檢出 | 檢出選定的項目。 |
|
||||||
| `` n `` | 新分支 | |
|
| `` n `` | 新分支 | |
|
||||||
| `` o `` | 建立拉取請求 | |
|
| `` o `` | 建立拉取請求 | |
|
||||||
| `` O `` | 建立拉取請求選項 | |
|
| `` O `` | 建立拉取請求選項 | |
|
||||||
| `` <c-y> `` | 複製拉取請求的 URL 到剪貼板 | |
|
| `` <c-y> `` | 複製拉取請求的 URL 到剪貼板 | |
|
||||||
| `` c `` | 根據名稱檢出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
| `` c `` | 根據名稱檢出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||||
| `` F `` | 強制檢出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
| `` F `` | 強制檢出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
| `` d `` | 刪除 | View delete options for local/remote branch. |
|
||||||
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` M `` | 合併到當前檢出的分支 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` f `` | 從上游快進此分支 | Fast-forward selected branch from its upstream. |
|
| `` f `` | 從上游快進此分支 | 從遠端快進所選的分支 |
|
||||||
| `` T `` | 建立標籤 | |
|
| `` T `` | 建立標籤 | |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | 排序規則 | |
|
||||||
| `` g `` | 檢視重設選項 | |
|
| `` g `` | 檢視重設選項 | |
|
||||||
| `` R `` | 重新命名分支 | |
|
| `` R `` | 重新命名分支 | |
|
||||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
| `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) |
|
||||||
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <enter> `` | 檢視提交 | |
|
| `` <enter> `` | 檢視提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 標籤
|
## 標籤
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <space> `` | 檢出 | Checkout the selected tag tag as a detached HEAD. |
|
| `` <c-o> `` | Copy tag to clipboard | |
|
||||||
|
| `` <space> `` | 檢出 | Checkout the selected tag as a detached HEAD. |
|
||||||
| `` n `` | 建立標籤 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
| `` n `` | 建立標籤 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
| `` d `` | 刪除 | View delete options for local/remote tag. |
|
||||||
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 重設 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <enter> `` | 檢視提交 | |
|
| `` <enter> `` | 檢視提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 檔案
|
## 檔案
|
||||||
|
|
||||||
@@ -294,35 +303,37 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||||
| `` <space> `` | 切換預存 | Toggle staged for selected file. |
|
| `` <space> `` | 切換預存 | Toggle staged for selected file. |
|
||||||
| `` <c-b> `` | 篩選檔案 (預存/未預存) | |
|
| `` <c-b> `` | 篩選檔案 (預存/未預存) | |
|
||||||
| `` y `` | Copy to clipboard | |
|
| `` y `` | 複製到剪貼簿 | |
|
||||||
| `` c `` | 提交變更 | Commit staged changes. |
|
| `` c `` | 提交變更 | 提交暫存區變更 |
|
||||||
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
||||||
| `` A `` | 修正上次提交 | |
|
| `` A `` | 修改上次提交 | |
|
||||||
| `` C `` | 使用 git 編輯器提交變更 | |
|
| `` 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> |
|
| `` <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> |
|
||||||
| `` e `` | Edit | Open file in external editor. |
|
| `` e `` | 編輯 | 使用外部編輯器開啟 |
|
||||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||||
| `` i `` | 忽略或排除檔案 | |
|
| `` i `` | 忽略或排除檔案 | |
|
||||||
| `` r `` | 重新整理檔案 | |
|
| `` r `` | 重新整理檔案 | |
|
||||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
| `` s `` | 收藏 | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||||
| `` S `` | 檢視收藏選項 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
| `` S `` | 檢視收藏選項 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||||
| `` a `` | 全部預存/取消預存 | Toggle staged/unstaged for all files in working tree. |
|
| `` a `` | 全部預存/取消預存 | Toggle staged/unstaged for all files in working tree. |
|
||||||
| `` <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. |
|
| `` <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. |
|
||||||
| `` d `` | 檢視“捨棄更改”的選項 | View options for discarding changes to the selected file. |
|
| `` d `` | 捨棄 | 檢視選中變動進行捨棄復原 |
|
||||||
| `` g `` | 檢視上游重設選項 | |
|
| `` g `` | 檢視遠端重設選項 | |
|
||||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
| `` D `` | 重設 | View reset options for working tree (e.g. nuking the working tree). |
|
||||||
| `` ` `` | 切換檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` M `` | 開啟外部合併工具 (git mergetool) | Run `git mergetool`. |
|
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
||||||
| `` f `` | 擷取 | Fetch changes from remote. |
|
| `` f `` | 擷取 | 同步遠端異動 |
|
||||||
| `` / `` | 開始搜尋 | |
|
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||||
|
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||||
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 狀態
|
## 狀態
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` o `` | 開啟設定檔案 | Open file in default application. |
|
| `` o `` | 開啟設定檔案 | 使用預設軟體開啟 |
|
||||||
| `` e `` | 編輯設定檔案 | Open file in external editor. |
|
| `` e `` | 編輯設定檔案 | 使用外部編輯器開啟 |
|
||||||
| `` u `` | 檢查更新 | |
|
| `` u `` | 檢查更新 | |
|
||||||
| `` <enter> `` | 切換到最近使用的版本庫 | |
|
| `` <enter> `` | 切換到最近使用的版本庫 | |
|
||||||
| `` a `` | 顯示所有分支日誌 | |
|
| `` a `` | 顯示所有分支日誌 | |
|
||||||
@@ -341,23 +352,24 @@ If you would instead like to start an interactive rebase from the selected commi
|
|||||||
| `` <enter> `` | View branches | |
|
| `` <enter> `` | View branches | |
|
||||||
| `` n `` | 新增遠端 | |
|
| `` n `` | 新增遠端 | |
|
||||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||||
| `` e `` | Edit | 編輯遠端 |
|
| `` e `` | 編輯 | 編輯遠端 |
|
||||||
| `` f `` | 擷取 | 擷取遠端 |
|
| `` f `` | 擷取 | 擷取遠端 |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|
||||||
## 遠端分支
|
## 遠端分支
|
||||||
|
|
||||||
| Key | Action | Info |
|
| Key | Action | Info |
|
||||||
|-----|--------|-------------|
|
|-----|--------|-------------|
|
||||||
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
||||||
| `` <space> `` | 檢出 | Checkout a new local branch based on the selected remote branch. The new branch will track the remote branch. |
|
| `` <space> `` | 檢出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||||
| `` n `` | 新分支 | |
|
| `` n `` | 新分支 | |
|
||||||
| `` M `` | 合併到當前檢出的分支 | Merge selected branch into currently checked out branch. |
|
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||||
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
| `` d `` | 刪除 | Delete the remote branch from the remote. |
|
||||||
| `` u `` | Set as upstream | 將此分支設為當前分支之上游 |
|
| `` u `` | 設置為遠端 | 將此分支設為當前分支之遠端 |
|
||||||
| `` s `` | Sort order | |
|
| `` s `` | 排序規則 | |
|
||||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||||
|
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||||
| `` <enter> `` | 檢視提交 | |
|
| `` <enter> `` | 檢視提交 | |
|
||||||
| `` w `` | View worktree options | |
|
| `` w `` | 檢視工作目錄選項 | |
|
||||||
| `` / `` | Filter the current view by text | |
|
| `` / `` | 搜尋 | |
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
module github.com/jesseduffield/lazygit
|
module github.com/jesseduffield/lazygit
|
||||||
|
|
||||||
go 1.20
|
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/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.8.1
|
||||||
github.com/gdamore/tcell/v2 v2.7.1-0.20240121011954-0393f5eb0b1a
|
|
||||||
github.com/go-errors/errors v1.5.1
|
github.com/go-errors/errors v1.5.1
|
||||||
github.com/gookit/color v1.4.2
|
github.com/gookit/color v1.4.2
|
||||||
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.20240129213945-26fc8669eb5b
|
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
|
||||||
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/jesseduffield/yaml v2.1.0+incompatible
|
|
||||||
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/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.15
|
github.com/mattn/go-runewidth v0.0.16
|
||||||
github.com/mgutz/str v1.2.0
|
github.com/mgutz/str v1.2.0
|
||||||
github.com/mitchellh/go-ps 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.5
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/spf13/afero v1.9.5
|
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/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2
|
||||||
github.com/stretchr/testify v1.8.1
|
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/exp v0.0.0-20220318154914-8dddf5d87bd8
|
||||||
|
golang.org/x/sync v0.11.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
|
||||||
)
|
)
|
||||||
@@ -48,12 +48,11 @@ require (
|
|||||||
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/invopop/jsonschema v0.10.0 // 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
|
||||||
@@ -66,16 +65,16 @@ require (
|
|||||||
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-20240813172612-4fcff4a6cae7 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.6 // 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/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-20220722155217-630584e8d5aa // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/term v0.16.0 // indirect
|
golang.org/x/term v0.29.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
|||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
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/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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/OpenPeeDeeP/xdg v1.0.0 h1:UDLmNjCGFZZCaVMB74DqYEtXkHxnTxcr4FeJVF9uCn8=
|
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||||
github.com/OpenPeeDeeP/xdg v1.0.0/go.mod h1:tMoSueLQlMf0TCldjrJLNIjAc5qAOIcHt5REi88/Ygo=
|
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=
|
||||||
@@ -84,14 +84,12 @@ github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9
|
|||||||
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/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.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
|
||||||
github.com/gdamore/tcell/v2 v2.7.1-0.20240103180601-96e29905643b/go.mod h1:hl/KtAANGBecfIPxk+FzKvThTqI84oplgbPEmVX60b8=
|
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||||
github.com/gdamore/tcell/v2 v2.7.1-0.20240121011954-0393f5eb0b1a h1:IgatwqPZL0RPblLezzibmx8GgARDjOQOvrLpCWLmZak=
|
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
|
||||||
github.com/gdamore/tcell/v2 v2.7.1-0.20240121011954-0393f5eb0b1a/go.mod h1:hl/KtAANGBecfIPxk+FzKvThTqI84oplgbPEmVX60b8=
|
github.com/gdamore/tcell/v2 v2.8.1/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
|
||||||
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=
|
||||||
@@ -147,8 +145,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.1/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.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.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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
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.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/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
@@ -188,16 +186,14 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
|
|||||||
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.20240129213945-26fc8669eb5b h1:QASuIUc76BuFmSuzzqwzjpsn23r8ybfDqbKsY2WzTrE=
|
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac h1:vUNTiVEB9Bz16pTJ5kNgb/1HhnWdSA1P0GfFLUJeITI=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20240129213945-26fc8669eb5b/go.mod h1:9zkyjnUmdL3+sUknJrQy/3HweUu8mVln/3J2wRF/l8M=
|
github.com/jesseduffield/gocui v0.3.1-0.20250220081214-b376cb0857ac/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/go.mod h1:qxN4mHOAyeIDLP7IK7defgPClM/z1Kze8VVQiaEjzsQ=
|
||||||
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/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
|
|
||||||
github.com/jesseduffield/yaml v2.1.0+incompatible/go.mod h1:w0xGhOSIJCGYYW+hnFPTutCy5aACpkcwbmORt5axGqk=
|
|
||||||
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/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.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
@@ -237,8 +233,8 @@ 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.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/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=
|
||||||
@@ -252,8 +248,8 @@ github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
|||||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
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-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
|
||||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
|
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||||
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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -264,8 +260,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
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.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.6/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/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=
|
||||||
@@ -273,8 +269,8 @@ github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM=
|
|||||||
github.com/samber/lo v1.31.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
github.com/samber/lo v1.31.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
||||||
github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw=
|
github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw=
|
||||||
github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
|
github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
|
||||||
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
|
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
|
||||||
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
|
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
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=
|
||||||
@@ -283,10 +279,11 @@ 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/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/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
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=
|
||||||
@@ -299,6 +296,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
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 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||||
@@ -326,8 +324,12 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
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-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/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -365,6 +367,9 @@ 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.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/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-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=
|
||||||
@@ -400,8 +405,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
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.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -423,6 +432,12 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||||
|
golang.org/x/sync v0.11.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-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=
|
||||||
@@ -467,18 +482,28 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
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.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
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-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.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
|
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||||
|
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -488,8 +513,13 @@ 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.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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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-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/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -542,6 +572,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
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/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
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-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=
|
||||||
|
|||||||
+28
-24
@@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
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"
|
||||||
@@ -64,22 +63,20 @@ 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()
|
appState := config.GetAppState()
|
||||||
|
|
||||||
var err error
|
|
||||||
log := newLogger(config)
|
log := newLogger(config)
|
||||||
tr, err := i18n.NewTranslationSetFromConfig(log, userConfig.Gui.Language)
|
// Initialize with English for the time being; the real translation set for
|
||||||
if err != nil {
|
// the configured language will be read after reading the user config
|
||||||
return nil, err
|
tr := i18n.EnglishTranslationSet()
|
||||||
}
|
|
||||||
|
|
||||||
return &common.Common{
|
cmn := &common.Common{
|
||||||
Log: log,
|
Log: log,
|
||||||
Tr: tr,
|
Tr: tr,
|
||||||
UserConfig: userConfig,
|
AppState: appState,
|
||||||
AppState: appState,
|
Debug: config.GetDebug(),
|
||||||
Debug: config.GetDebug(),
|
Fs: afero.NewOsFs(),
|
||||||
Fs: afero.NewOsFs(),
|
}
|
||||||
}, nil
|
cmn.SetUserConfig(userConfig)
|
||||||
|
return cmn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
||||||
@@ -119,7 +116,14 @@ func NewApp(config config.AppConfigurer, test integrationTypes.IntegrationTest,
|
|||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
|
|
||||||
showRecentRepos, err := app.setupRepo()
|
// If we're not in a repo, GetRepoPaths will return an error. 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 {
|
||||||
|
common.Log.Infof("Error getting repo paths: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
showRecentRepos, err := app.setupRepo(repoPaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return app, err
|
return app, err
|
||||||
}
|
}
|
||||||
@@ -168,14 +172,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
|
||||||
@@ -187,7 +193,7 @@ func (app *App) setupRepo() (bool, error) {
|
|||||||
|
|
||||||
var shouldInitRepo bool
|
var shouldInitRepo bool
|
||||||
initialBranchArg := ""
|
initialBranchArg := ""
|
||||||
switch app.UserConfig.NotARepository {
|
switch app.UserConfig().NotARepository {
|
||||||
case "prompt":
|
case "prompt":
|
||||||
// Offer to initialize a new repository in current directory.
|
// Offer to initialize a new repository in current directory.
|
||||||
fmt.Print(app.Tr.CreateRepo)
|
fmt.Print(app.Tr.CreateRepo)
|
||||||
@@ -221,6 +227,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,10 +245,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)
|
||||||
|
|
||||||
|
|||||||
+106
-34
@@ -8,7 +8,6 @@ import (
|
|||||||
"os/exec"
|
"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/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
@@ -33,12 +32,15 @@ const (
|
|||||||
DaemonKindUnknown DaemonKind = iota
|
DaemonKindUnknown DaemonKind = iota
|
||||||
|
|
||||||
DaemonKindExitImmediately
|
DaemonKindExitImmediately
|
||||||
|
DaemonKindRemoveUpdateRefsForCopiedBranch
|
||||||
DaemonKindCherryPick
|
DaemonKindCherryPick
|
||||||
DaemonKindMoveTodosUp
|
DaemonKindMoveTodosUp
|
||||||
DaemonKindMoveTodosDown
|
DaemonKindMoveTodosDown
|
||||||
DaemonKindInsertBreak
|
DaemonKindInsertBreak
|
||||||
DaemonKindChangeTodoActions
|
DaemonKindChangeTodoActions
|
||||||
|
DaemonKindDropMergeCommit
|
||||||
DaemonKindMoveFixupCommitDown
|
DaemonKindMoveFixupCommitDown
|
||||||
|
DaemonKindWriteRebaseTodo
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -52,13 +54,16 @@ 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],
|
||||||
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
DaemonKindDropMergeCommit: deserializeInstruction[*DropMergeCommitInstruction],
|
||||||
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
||||||
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
||||||
|
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
||||||
|
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
|
||||||
|
DaemonKindWriteRebaseTodo: deserializeInstruction[*WriteRebaseTodoInstruction],
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping[getDaemonKind()](jsonData)
|
return mapping[getDaemonKind()](jsonData)
|
||||||
@@ -155,6 +160,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
|
||||||
}
|
}
|
||||||
@@ -210,8 +235,7 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
|||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
|
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
|
||||||
return utils.TodoChange{
|
return utils.TodoChange{
|
||||||
Sha: c.Sha,
|
Hash: c.Hash,
|
||||||
OldAction: todo.Pick,
|
|
||||||
NewAction: c.NewAction,
|
NewAction: c.NewAction,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -220,18 +244,44 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes the sha of some commit, and the sha of a fixup commit that was created
|
type DropMergeCommitInstruction struct {
|
||||||
// at the end of the branch, then moves the fixup commit down to right after the
|
Hash string
|
||||||
// original commit, changing its type to "fixup"
|
|
||||||
type MoveFixupCommitDownInstruction struct {
|
|
||||||
OriginalSha string
|
|
||||||
FixupSha string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveFixupCommitDownInstruction(originalSha string, fixupSha string) Instruction {
|
func NewDropMergeCommitInstruction(hash string) Instruction {
|
||||||
|
return &DropMergeCommitInstruction{
|
||||||
|
Hash: hash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DropMergeCommitInstruction) Kind() DaemonKind {
|
||||||
|
return DaemonKindDropMergeCommit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DropMergeCommitInstruction) SerializedInstructions() string {
|
||||||
|
return serializeInstruction(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *DropMergeCommitInstruction) run(common *common.Common) error {
|
||||||
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
|
return utils.DropMergeCommit(path, self.Hash, getCommentChar())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// original commit, changing its type to "fixup" (only if ChangeToFixup is true)
|
||||||
|
type MoveFixupCommitDownInstruction struct {
|
||||||
|
OriginalHash string
|
||||||
|
FixupHash string
|
||||||
|
ChangeToFixup bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMoveFixupCommitDownInstruction(originalHash string, fixupHash string, changeToFixup bool) Instruction {
|
||||||
return &MoveFixupCommitDownInstruction{
|
return &MoveFixupCommitDownInstruction{
|
||||||
OriginalSha: originalSha,
|
OriginalHash: originalHash,
|
||||||
FixupSha: fixupSha,
|
FixupHash: fixupHash,
|
||||||
|
ChangeToFixup: changeToFixup,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,17 +295,17 @@ 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, self.ChangeToFixup, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodosUpInstruction struct {
|
type MoveTodosUpInstruction struct {
|
||||||
Shas []string
|
Hashes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodosUpInstruction(shas []string) Instruction {
|
func NewMoveTodosUpInstruction(hashes []string) Instruction {
|
||||||
return &MoveTodosUpInstruction{
|
return &MoveTodosUpInstruction{
|
||||||
Shas: shas,
|
Hashes: hashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,25 +318,24 @@ func (self *MoveTodosUpInstruction) SerializedInstructions() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
|
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
|
||||||
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
|
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||||
return utils.Todo{
|
return utils.Todo{
|
||||||
Sha: sha,
|
Hash: hash,
|
||||||
Action: todo.Pick,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodosUp(path, todosToMove, getCommentChar())
|
return utils.MoveTodosUp(path, todosToMove, false, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type MoveTodosDownInstruction struct {
|
type MoveTodosDownInstruction struct {
|
||||||
Shas []string
|
Hashes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMoveTodosDownInstruction(shas []string) Instruction {
|
func NewMoveTodosDownInstruction(hashes []string) Instruction {
|
||||||
return &MoveTodosDownInstruction{
|
return &MoveTodosDownInstruction{
|
||||||
Shas: shas,
|
Hashes: hashes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,15 +348,14 @@ func (self *MoveTodosDownInstruction) SerializedInstructions() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
|
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
|
||||||
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
|
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||||
return utils.Todo{
|
return utils.Todo{
|
||||||
Sha: sha,
|
Hash: hash,
|
||||||
Action: todo.Pick,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return handleInteractiveRebase(common, func(path string) error {
|
return handleInteractiveRebase(common, func(path string) error {
|
||||||
return utils.MoveTodosDown(path, todosToMove, getCommentChar())
|
return utils.MoveTodosDown(path, todosToMove, false, getCommentChar())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,3 +378,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/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/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TodoLine struct {
|
type TodoLine struct {
|
||||||
@@ -21,7 +22,7 @@ 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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ func TodoLinesToString(todoLines []TodoLine) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
+33
-7
@@ -4,6 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -27,15 +29,17 @@ type cliArgs struct {
|
|||||||
RepoPath string
|
RepoPath string
|
||||||
FilterPath string
|
FilterPath string
|
||||||
GitArg string
|
GitArg string
|
||||||
PrintVersionInfo bool
|
|
||||||
Debug bool
|
|
||||||
TailLogs bool
|
|
||||||
PrintDefaultConfig bool
|
|
||||||
PrintConfigDir bool
|
|
||||||
UseConfigDir string
|
UseConfigDir string
|
||||||
WorkTree string
|
WorkTree string
|
||||||
GitDir string
|
GitDir string
|
||||||
CustomConfigFile string
|
CustomConfigFile string
|
||||||
|
ScreenMode string
|
||||||
|
PrintVersionInfo bool
|
||||||
|
Debug bool
|
||||||
|
TailLogs bool
|
||||||
|
Profile bool
|
||||||
|
PrintDefaultConfig bool
|
||||||
|
PrintConfigDir bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildInfo struct {
|
type BuildInfo struct {
|
||||||
@@ -133,6 +137,12 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
|
|||||||
|
|
||||||
if integrationTest != nil {
|
if integrationTest != nil {
|
||||||
integrationTest.SetupConfig(appConfig)
|
integrationTest.SetupConfig(appConfig)
|
||||||
|
|
||||||
|
// Preserve the changes that the test setup just made to the config, so
|
||||||
|
// they don't get lost when we reload the config while running the test
|
||||||
|
// (which happens when switching between repos, going in and out of
|
||||||
|
// submodules, etc).
|
||||||
|
appConfig.SaveGlobalUserConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
common, err := NewCommon(appConfig)
|
common, err := NewCommon(appConfig)
|
||||||
@@ -145,9 +155,17 @@ 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, cliArgs.ScreenMode, integrationTest))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCliArgsAndEnvVars() *cliArgs {
|
func parseCliArgsAndEnvVars() *cliArgs {
|
||||||
@@ -171,6 +189,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")
|
||||||
|
|
||||||
@@ -189,6 +210,9 @@ func parseCliArgsAndEnvVars() *cliArgs {
|
|||||||
customConfigFile := ""
|
customConfigFile := ""
|
||||||
flaggy.String(&customConfigFile, "ucf", "use-config-file", "Comma separated list to custom config file(s)")
|
flaggy.String(&customConfigFile, "ucf", "use-config-file", "Comma separated list to custom config file(s)")
|
||||||
|
|
||||||
|
screenMode := ""
|
||||||
|
flaggy.String(&screenMode, "sm", "screen-mode", "The initial screen-mode, which determines the size of the focused panel. Valid options: 'normal' (default), 'half', 'full'")
|
||||||
|
|
||||||
flaggy.Parse()
|
flaggy.Parse()
|
||||||
|
|
||||||
if os.Getenv("DEBUG") == "TRUE" {
|
if os.Getenv("DEBUG") == "TRUE" {
|
||||||
@@ -202,12 +226,14 @@ 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,
|
||||||
WorkTree: workTree,
|
WorkTree: workTree,
|
||||||
GitDir: gitDir,
|
GitDir: gitDir,
|
||||||
CustomConfigFile: customConfigFile,
|
CustomConfigFile: customConfigFile,
|
||||||
|
ScreenMode: screenMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +289,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
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import (
|
|||||||
|
|
||||||
// StartArgs is the struct that represents some things we want to do on program start
|
// StartArgs is the struct that represents some things we want to do on program start
|
||||||
type StartArgs struct {
|
type StartArgs struct {
|
||||||
// FilterPath determines which path we're going to filter on so that we only see commits from that file.
|
|
||||||
FilterPath string
|
|
||||||
// GitArg determines what context we open in
|
// GitArg determines what context we open in
|
||||||
GitArg GitArg
|
GitArg GitArg
|
||||||
// integration test (only relevant when invoking lazygit in the context of an integration test)
|
// integration test (only relevant when invoking lazygit in the context of an integration test)
|
||||||
IntegrationTest integrationTypes.IntegrationTest
|
IntegrationTest integrationTypes.IntegrationTest
|
||||||
|
// FilterPath determines which path we're going to filter on so that we only see commits from that file.
|
||||||
|
FilterPath string
|
||||||
|
// ScreenMode determines the initial Screen Mode (normal, half or full) to use
|
||||||
|
ScreenMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitArg string
|
type GitArg string
|
||||||
@@ -24,10 +26,11 @@ const (
|
|||||||
GitArgStash GitArg = "stash"
|
GitArgStash GitArg = "stash"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStartArgs(filterPath string, gitArg GitArg, test integrationTypes.IntegrationTest) StartArgs {
|
func NewStartArgs(filterPath string, gitArg GitArg, screenMode string, test integrationTypes.IntegrationTest) StartArgs {
|
||||||
return StartArgs{
|
return StartArgs{
|
||||||
FilterPath: filterPath,
|
FilterPath: filterPath,
|
||||||
GitArg: gitArg,
|
GitArg: gitArg,
|
||||||
|
ScreenMode: screenMode,
|
||||||
IntegrationTest: test,
|
IntegrationTest: test,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,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 {
|
||||||
@@ -60,6 +63,11 @@ func generateAtDir(cheatsheetDir string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
tr, err := i18n.NewTranslationSetFromConfig(common.Log, lang)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
common.Tr = tr
|
||||||
mApp, _ := app.NewApp(mConfig, nil, 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)
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -134,7 +134,7 @@ func NewGitCommandAux(
|
|||||||
worktreeCommands := git_commands.NewWorktreeCommands(gitCommon)
|
worktreeCommands := git_commands.NewWorktreeCommands(gitCommon)
|
||||||
blameCommands := git_commands.NewBlameCommands(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, statusCommands.RebaseMode, gitCommon)
|
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.RebaseMode, gitCommon)
|
||||||
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ func (self *gitCmdObjBuilder) NewShell(cmdStr string) oscommands.ICmdObj {
|
|||||||
return self.innerBuilder.NewShell(cmdStr).AddEnvVars(defaultEnvVar)
|
return self.innerBuilder.NewShell(cmdStr).AddEnvVars(defaultEnvVar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *gitCmdObjBuilder) NewInteractiveShell(cmdStr string) oscommands.ICmdObj {
|
||||||
|
return self.innerBuilder.NewInteractiveShell(cmdStr).AddEnvVars(defaultEnvVar)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *gitCmdObjBuilder) Quote(str string) string {
|
func (self *gitCmdObjBuilder) Quote(str string) string {
|
||||||
return self.innerBuilder.Quote(str)
|
return self.innerBuilder.Quote(str)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *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
|
||||||
@@ -86,7 +86,7 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
|
|||||||
status = BisectStatusSkipped
|
status = BisectStatusSkipped
|
||||||
}
|
}
|
||||||
|
|
||||||
info.statusMap[sha] = status
|
info.statusMap[hash] = status
|
||||||
}
|
}
|
||||||
|
|
||||||
currentContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_EXPECTED_REV"))
|
currentContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_EXPECTED_REV"))
|
||||||
@@ -94,8 +94,8 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
|
|||||||
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
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ func (self *BisectCommands) StartWithTerms(oldTerm string, newTerm string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
@@ -143,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,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
|
||||||
@@ -185,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()
|
||||||
|
|||||||
@@ -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,7 +93,7 @@ func (self *BisectInfo) Bisecting() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.GetNewSha() == "" {
|
if self.GetNewHash() == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"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/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 +31,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 +77,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
|
||||||
@@ -86,10 +109,10 @@ func (self *BranchCommands) CurrentBranchName() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LocalDelete delete branch locally
|
// LocalDelete delete branch locally
|
||||||
func (self *BranchCommands) LocalDelete(branch string, force bool) error {
|
func (self *BranchCommands) LocalDelete(branches []string, force bool) error {
|
||||||
cmdArgs := NewGitCmd("branch").
|
cmdArgs := NewGitCmd("branch").
|
||||||
ArgIfElse(force, "-D", "-d").
|
ArgIfElse(force, "-D", "-d").
|
||||||
Arg(branch).
|
Arg(branches...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
@@ -123,7 +146,7 @@ func (self *BranchCommands) GetGraph(branchName string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj {
|
func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj {
|
||||||
branchLogCmdTemplate := self.UserConfig.Git.BranchLogCmd
|
branchLogCmdTemplate := self.UserConfig().Git.BranchLogCmd
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"branchName": self.cmd.Quote(branchName),
|
"branchName": self.cmd.Quote(branchName),
|
||||||
}
|
}
|
||||||
@@ -205,13 +228,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()
|
||||||
|
|
||||||
@@ -219,5 +247,41 @@ 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *BranchCommands) IsBranchMerged(branch *models.Branch, mainBranches *MainBranches) (bool, error) {
|
||||||
|
branchesToCheckAgainst := []string{"HEAD"}
|
||||||
|
if branch.RemoteBranchStoredLocally() {
|
||||||
|
branchesToCheckAgainst = append(branchesToCheckAgainst, fmt.Sprintf("%s@{upstream}", branch.Name))
|
||||||
|
}
|
||||||
|
branchesToCheckAgainst = append(branchesToCheckAgainst, mainBranches.Get()...)
|
||||||
|
|
||||||
|
cmdArgs := NewGitCmd("rev-list").
|
||||||
|
Arg("--max-count=1").
|
||||||
|
Arg(branch.Name).
|
||||||
|
Arg(lo.Map(branchesToCheckAgainst, func(branch string, _ int) string {
|
||||||
|
return fmt.Sprintf("^%s", branch)
|
||||||
|
})...).
|
||||||
|
Arg("--").
|
||||||
|
ToArgv()
|
||||||
|
|
||||||
|
stdout, _, err := self.cmd.New(cmdArgs).RunWithOutputs()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout == "", nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/set"
|
"github.com/jesseduffield/generics/set"
|
||||||
"github.com/jesseduffield/go-git/v5/config"
|
"github.com/jesseduffield/go-git/v5/config"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
"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/exp/slices"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
// context:
|
// context:
|
||||||
@@ -40,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
|
||||||
@@ -47,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,
|
||||||
@@ -60,8 +65,14 @@ 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))
|
||||||
|
|
||||||
if self.AppState.LocalBranchSortOrder == "recency" {
|
if self.AppState.LocalBranchSortOrder == "recency" {
|
||||||
reflogBranches := self.obtainReflogBranches(reflogCommits)
|
reflogBranches := self.obtainReflogBranches(reflogCommits)
|
||||||
@@ -119,12 +130,109 @@ func (self *BranchLoader) Load(reflogCommits []*models.Commit) ([]*models.Branch
|
|||||||
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)
|
||||||
@@ -147,7 +255,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
storeCommitDateAsRecency := self.AppState.LocalBranchSortOrder != "recency"
|
storeCommitDateAsRecency := self.AppState.LocalBranchSortOrder != "recency"
|
||||||
return obtainBranch(split, storeCommitDateAsRecency), true
|
return obtainBranch(split, storeCommitDateAsRecency, canUsePushTrack), true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,23 +291,31 @@ var branchFields = []string{
|
|||||||
"refname:short",
|
"refname:short",
|
||||||
"upstream:short",
|
"upstream:short",
|
||||||
"upstream:track",
|
"upstream:track",
|
||||||
|
"push:track",
|
||||||
"subject",
|
"subject",
|
||||||
"objectname",
|
"objectname",
|
||||||
"committerdate:unix",
|
"committerdate:unix",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain branch information from parsed line output of getRawBranches()
|
// Obtain branch information from parsed line output of getRawBranches()
|
||||||
func obtainBranch(split []string, storeCommitDateAsRecency bool) *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]
|
||||||
commitDate := split[6]
|
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 := ""
|
recency := ""
|
||||||
if storeCommitDateAsRecency {
|
if storeCommitDateAsRecency {
|
||||||
@@ -209,14 +325,16 @@ func obtainBranch(split []string, storeCommitDateAsRecency bool) *models.Branch
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &models.Branch{
|
return &models.Branch{
|
||||||
Name: name,
|
Name: name,
|
||||||
Recency: recency,
|
Recency: recency,
|
||||||
Pushables: pushables,
|
AheadForPull: aheadForPull,
|
||||||
Pullables: pullables,
|
BehindForPull: behindForPull,
|
||||||
UpstreamGone: gone,
|
AheadForPush: aheadForPush,
|
||||||
Head: headMarker == "*",
|
BehindForPush: behindForPush,
|
||||||
Subject: subject,
|
UpstreamGone: gone,
|
||||||
CommitHash: commitHash,
|
Head: headMarker == "*",
|
||||||
|
Subject: subject,
|
||||||
|
CommitHash: commitHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,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 {
|
||||||
|
|||||||
@@ -25,89 +25,101 @@ func TestObtainBranch(t *testing.T) {
|
|||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "TrimHeads",
|
testName: "TrimHeads",
|
||||||
input: []string{"", "heads/a_branch", "", "", "subject", "123", timeStamp},
|
input: []string{"", "heads/a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: false,
|
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", timeStamp},
|
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: false,
|
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", timeStamp},
|
input: []string{"*", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: false,
|
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", timeStamp},
|
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "[behind 2, ahead 3]", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: false,
|
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", timeStamp},
|
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "[gone]", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: false,
|
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",
|
testName: "WithCommitDateAsRecency",
|
||||||
input: []string{"", "a_branch", "", "", "subject", "123", timeStamp},
|
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
|
||||||
storeCommitDateAsRecency: true,
|
storeCommitDateAsRecency: true,
|
||||||
expectedBranch: &models.Branch{
|
expectedBranch: &models.Branch{
|
||||||
Name: "a_branch",
|
Name: "a_branch",
|
||||||
Recency: "2h",
|
Recency: "2h",
|
||||||
Pushables: "?",
|
AheadForPull: "?",
|
||||||
Pullables: "?",
|
BehindForPull: "?",
|
||||||
Head: false,
|
AheadForPush: "?",
|
||||||
Subject: "subject",
|
BehindForPush: "?",
|
||||||
CommitHash: "123",
|
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, s.storeCommitDateAsRecency)
|
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}")
|
||||||
@@ -63,37 +62,57 @@ func TestBranchNewBranch(t *testing.T) {
|
|||||||
|
|
||||||
func TestBranchDeleteBranch(t *testing.T) {
|
func TestBranchDeleteBranch(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
force bool
|
branchNames []string
|
||||||
runner *oscommands.FakeCmdObjRunner
|
force bool
|
||||||
test func(error)
|
runner *oscommands.FakeCmdObjRunner
|
||||||
|
test func(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"Delete a branch",
|
"Delete a branch",
|
||||||
|
[]string{"test"},
|
||||||
false,
|
false,
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-d", "test"}, "", nil),
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-d", "test"}, "", nil),
|
||||||
func(err error) {
|
func(err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Delete multiple branches",
|
||||||
|
[]string{"test1", "test2", "test3"},
|
||||||
|
false,
|
||||||
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-d", "test1", "test2", "test3"}, "", nil),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Force delete a branch",
|
"Force delete a branch",
|
||||||
|
[]string{"test"},
|
||||||
true,
|
true,
|
||||||
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-D", "test"}, "", nil),
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-D", "test"}, "", nil),
|
||||||
func(err error) {
|
func(err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Force delete multiple branches",
|
||||||
|
[]string{"test1", "test2", "test3"},
|
||||||
|
true,
|
||||||
|
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-D", "test1", "test2", "test3"}, "", nil),
|
||||||
|
func(err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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.LocalDelete("test", s.force))
|
s.test(instance.LocalDelete(s.branchNames, s.force))
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -127,6 +146,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 +169,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 +208,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 +296,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())
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ func (self *CommitCommands) SetAuthor(value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a commit's coauthor using Github/Gitlab Co-authored-by metadata. Value is expected to be of the form 'Name <Email>'
|
// 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(sha string, value string) error {
|
func (self *CommitCommands) AddCoAuthor(hash string, author string) error {
|
||||||
message, err := self.GetCommitMessage(sha)
|
message, err := self.GetCommitMessage(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message = message + fmt.Sprintf("\nCo-authored-by: %s", value)
|
message = AddCoAuthorToMessage(message, author)
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
Arg("--allow-empty", "--amend", "--only", "-m", message).
|
Arg("--allow-empty", "--amend", "--only", "-m", message).
|
||||||
@@ -54,9 +54,28 @@ func (self *CommitCommands) AddCoAuthor(sha string, value string) error {
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
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
|
||||||
@@ -69,7 +88,7 @@ func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars [
|
|||||||
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
|
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
|
||||||
messageArgs := self.commitMessageArgs(summary, description)
|
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(summary, skipHookPrefix), "--no-verify").
|
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
|
||||||
@@ -98,7 +117,7 @@ func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RewordLastCommit rewords the topmost commit with the given message
|
// RewordLastCommit rewords the topmost commit with the given message
|
||||||
func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
|
func (self *CommitCommands) RewordLastCommit(summary string, description string) oscommands.ICmdObj {
|
||||||
messageArgs := self.commitMessageArgs(summary, description)
|
messageArgs := self.commitMessageArgs(summary, description)
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("commit").
|
cmdArgs := NewGitCmd("commit").
|
||||||
@@ -106,7 +125,7 @@ func (self *CommitCommands) RewordLastCommit(summary string, description string)
|
|||||||
Arg(messageArgs...).
|
Arg(messageArgs...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
|
func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
|
||||||
@@ -129,33 +148,35 @@ func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) signoffFlag() string {
|
func (self *CommitCommands) signoffFlag() string {
|
||||||
if self.UserConfig.Git.Commit.SignOff {
|
if self.UserConfig().Git.Commit.SignOff {
|
||||||
return "--signoff"
|
return "--signoff"
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
|
func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
Arg("--format=%B", "--max-count=1", commitSha).
|
Arg("--format=%B", "--max-count=1", commitHash).
|
||||||
|
Config("log.showsignature=false").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
return strings.TrimSpace(message), err
|
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitSubject(commitSha string) (string, error) {
|
func (self *CommitCommands) GetCommitSubject(commitHash string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
Arg("--format=%s", "--max-count=1", commitSha).
|
Arg("--format=%s", "--max-count=1", commitHash).
|
||||||
|
Config("log.showsignature=false").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
subject, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
subject, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||||
return strings.TrimSpace(subject), err
|
return strings.TrimSpace(subject), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) GetCommitDiff(commitSha string) (string, error) {
|
func (self *CommitCommands) GetCommitDiff(commitHash string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("show").Arg("--no-color", commitSha).ToArgv()
|
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
|
||||||
@@ -166,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()
|
||||||
@@ -185,14 +206,14 @@ 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()
|
||||||
@@ -203,19 +224,19 @@ func (self *CommitCommands) GetCommitMessagesFirstLine(shas []string) (string, e
|
|||||||
// cd50c79ae Preserve the commit message correctly even if the description has blank lines
|
// cd50c79ae Preserve the commit message correctly even if the description has blank lines
|
||||||
// 3ebba5f32 Add test demonstrating a bug with preserving the commit message
|
// 3ebba5f32 Add test demonstrating a bug with preserving the commit message
|
||||||
// 9a423c388 Remove unused function
|
// 9a423c388 Remove unused function
|
||||||
func (self *CommitCommands) GetShasAndCommitMessagesFirstLine(shas []string) (string, error) {
|
func (self *CommitCommands) GetHashesAndCommitMessagesFirstLine(hashes []string) (string, error) {
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
Arg("--no-patch", "--pretty=format:%h %s").
|
Arg("--no-patch", "--pretty=format:%h %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) {
|
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()
|
||||||
@@ -234,21 +255,23 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
|
|||||||
return self.cmd.New(cmdArgs)
|
return self.cmd.New(cmdArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands.ICmdObj {
|
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
|
||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
|
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
cmdArgs := NewGitCmd("show").
|
cmdArgs := NewGitCmd("show").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
|
||||||
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
|
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(self.AppState.IgnoreWhitespaceInDiffView, "--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).
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -256,23 +279,38 @@ func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands
|
|||||||
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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,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").
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"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/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/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// context:
|
// context:
|
||||||
@@ -35,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +51,6 @@ func NewCommitLoader(
|
|||||||
getRebaseMode: getRebaseMode,
|
getRebaseMode: getRebaseMode,
|
||||||
readFile: os.ReadFile,
|
readFile: os.ReadFile,
|
||||||
walkFiles: filepath.Walk,
|
walkFiles: filepath.Walk,
|
||||||
mainBranches: nil,
|
|
||||||
GitCommon: gitCommon,
|
GitCommon: gitCommon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,6 +58,7 @@ 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
|
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
|
||||||
@@ -71,6 +66,7 @@ type GetCommitsOptions struct {
|
|||||||
All bool
|
All bool
|
||||||
// If non-empty, show divergence from this ref (left-right log)
|
// If non-empty, show divergence from this ref (left-right log)
|
||||||
RefToShowDivergenceFrom string
|
RefToShowDivergenceFrom string
|
||||||
|
MainBranches *MainBranches
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommits obtains the commits of the current branch
|
// GetCommits obtains the commits of the current branch
|
||||||
@@ -107,9 +103,9 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
|
|||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
ancestor = self.getMergeBase(opts.RefName)
|
ancestor = opts.MainBranches.GetMergeBase(opts.RefName)
|
||||||
if opts.RefToShowDivergenceFrom != "" {
|
if opts.RefToShowDivergenceFrom != "" {
|
||||||
remoteAncestor = self.getMergeBase(opts.RefToShowDivergenceFrom)
|
remoteAncestor = opts.MainBranches.GetMergeBase(opts.RefToShowDivergenceFrom)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -128,7 +124,7 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
if commit.Sha == firstPushedCommit {
|
if commit.Hash == firstPushedCommit {
|
||||||
passedFirstPushedCommit = true
|
passedFirstPushedCommit = true
|
||||||
}
|
}
|
||||||
if commit.Status != models.StatusRebasing {
|
if commit.Status != models.StatusRebasing {
|
||||||
@@ -197,24 +193,24 @@ 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, showDivergence bool) *models.Commit {
|
func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool) *models.Commit {
|
||||||
split := strings.SplitN(line, "\x00", 8)
|
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
|
divergence := models.DivergenceNone
|
||||||
if showDivergence {
|
if showDivergence {
|
||||||
divergence = lo.Ternary(split[7] == "<", models.DivergenceLeft, models.DivergenceRight)
|
divergence = lo.Ternary(split[6] == "<", models.DivergenceLeft, models.DivergenceRight)
|
||||||
}
|
}
|
||||||
|
message := split[7]
|
||||||
|
|
||||||
tags := []string{}
|
tags := []string{}
|
||||||
|
|
||||||
@@ -240,7 +236,7 @@ func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &models.Commit{
|
return &models.Commit{
|
||||||
Sha: sha,
|
Hash: hash,
|
||||||
Name: message,
|
Name: message,
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
ExtraInfo: extraInfo,
|
ExtraInfo: extraInfo,
|
||||||
@@ -253,17 +249,14 @@ func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 := lo.FilterMap(commits, func(commit *models.Commit, _ int) (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
|
||||||
@@ -272,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, false)
|
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 {
|
||||||
@@ -287,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)
|
||||||
@@ -313,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.repoPaths.WorktreeGitDirPath(), "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.repoPaths.WorktreeGitDirPath(), "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:
|
|
||||||
// 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.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
|
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "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{}
|
||||||
@@ -387,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,
|
||||||
@@ -403,20 +343,22 @@ 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 = utils.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 {
|
||||||
@@ -506,22 +448,6 @@ func (self *CommitLoader) getConflictedCommitImpl(todos []todo.Todo, doneTodos [
|
|||||||
return lastTodo.Commit
|
return lastTodo.Commit
|
||||||
}
|
}
|
||||||
|
|
||||||
// assuming the file starts like this:
|
|
||||||
// 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 setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
|
func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
|
||||||
if ancestor == "" {
|
if ancestor == "" {
|
||||||
return
|
return
|
||||||
@@ -529,8 +455,8 @@ func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
|
|||||||
|
|
||||||
passedAncestor := false
|
passedAncestor := false
|
||||||
for i, commit := range commits {
|
for i, commit := range commits {
|
||||||
// some commits aren't really commits and don't have sha's, such as the update-ref todo
|
// some commits aren't really commits and don't have hashes, such as the update-ref todo
|
||||||
if commit.Sha != "" && strings.HasPrefix(ancestor, commit.Sha) {
|
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 {
|
||||||
@@ -542,84 +468,6 @@ func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|
||||||
var existingBranches []string
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
mainBranches := self.UserConfig.Git.MainBranches
|
|
||||||
existingBranches = make([]string, len(mainBranches))
|
|
||||||
|
|
||||||
for i, branchName := range mainBranches {
|
|
||||||
wg.Add(1)
|
|
||||||
i := i
|
|
||||||
branchName := branchName
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func ignoringWarnings(commandOutput string) string {
|
func ignoringWarnings(commandOutput string) string {
|
||||||
trimmedOutput := strings.TrimSpace(commandOutput)
|
trimmedOutput := strings.TrimSpace(commandOutput)
|
||||||
split := strings.Split(trimmedOutput, "\n")
|
split := strings.Split(trimmedOutput, "\n")
|
||||||
@@ -630,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(
|
||||||
@@ -650,7 +498,7 @@ 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
|
refSpec := opts.RefName
|
||||||
if opts.RefToShowDivergenceFrom != "" {
|
if opts.RefToShowDivergenceFrom != "" {
|
||||||
@@ -659,11 +507,12 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
|
|||||||
|
|
||||||
cmdArgs := NewGitCmd("log").
|
cmdArgs := NewGitCmd("log").
|
||||||
Arg(refSpec).
|
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").
|
||||||
@@ -675,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%x00%m`
|
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s`
|
||||||
|
|||||||
@@ -5,25 +5,26 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/go-errors/errors"
|
"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|tag: 123, tag: 456|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 {
|
||||||
@@ -45,7 +46,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{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%x00%m", "--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,
|
||||||
@@ -57,7 +58,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "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%x00%m", "--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,
|
||||||
@@ -72,7 +73,7 @@ func TestGetCommits(t *testing.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", "mybranch", "mybranch@{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%x00%m", "--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,7 +114,7 @@ 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,
|
||||||
@@ -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,
|
||||||
@@ -209,7 +210,7 @@ func TestGetCommits(t *testing.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", "mybranch", "mybranch@{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%x00%m", "--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,
|
||||||
@@ -246,7 +247,7 @@ func TestGetCommits(t *testing.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", "mybranch", "mybranch@{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%x00%m", "--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,
|
||||||
@@ -282,7 +283,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{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%x00%m", "--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,
|
||||||
@@ -294,7 +295,7 @@ func TestGetCommits(t *testing.T) {
|
|||||||
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
|
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{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%x00%m", "--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) {
|
||||||
@@ -320,8 +322,10 @@ 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(common, 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,8 @@ 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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,29 +523,29 @@ func TestCommitLoader_setCommitMergedStatuses(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testName: "basic",
|
testName: "basic",
|
||||||
commits: []*models.Commit{
|
commits: []*models.Commit{
|
||||||
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
{Sha: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusPushed},
|
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
},
|
},
|
||||||
ancestor: "67890",
|
ancestor: "67890",
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
{Sha: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusMerged},
|
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusMerged},
|
||||||
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusMerged},
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusMerged},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "with update-ref",
|
testName: "with update-ref",
|
||||||
commits: []*models.Commit{
|
commits: []*models.Commit{
|
||||||
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
{Sha: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
||||||
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
},
|
},
|
||||||
ancestor: "deadbeef",
|
ancestor: "deadbeef",
|
||||||
expectedCommits: []*models.Commit{
|
expectedCommits: []*models.Commit{
|
||||||
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
|
||||||
{Sha: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
|
||||||
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,10 @@ func TestCommitRewordCommit(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})
|
||||||
|
|
||||||
assert.NoError(t, instance.RewordLastCommit(s.summary, s.description))
|
assert.NoError(t, instance.RewordLastCommit(s.summary, s.description).Run())
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -100,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
|
||||||
@@ -136,7 +134,6 @@ func TestCommitCommitEditorCmdObj(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
|
||||||
@@ -153,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)
|
||||||
}
|
}
|
||||||
@@ -161,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) {
|
||||||
@@ -171,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()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -182,65 +228,80 @@ 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 uint64
|
||||||
ignoreWhitespace bool
|
similarityThreshold int
|
||||||
extDiffCmd string
|
ignoreWhitespace bool
|
||||||
expected []string
|
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,
|
||||||
extDiffCmd: "",
|
ignoreWhitespace: false,
|
||||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
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,
|
||||||
extDiffCmd: "",
|
ignoreWhitespace: false,
|
||||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
|
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,
|
||||||
extDiffCmd: "",
|
ignoreWhitespace: false,
|
||||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
|
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,
|
||||||
extDiffCmd: "",
|
ignoreWhitespace: false,
|
||||||
expected: []string{"-C", "/path/to/worktree", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
|
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 with external diff command",
|
testName: "Show diff, ignoring whitespace",
|
||||||
filterPath: "",
|
filterPath: "",
|
||||||
contextSize: 3,
|
contextSize: 77,
|
||||||
ignoreWhitespace: false,
|
similarityThreshold: 50,
|
||||||
extDiffCmd: "difft --color=always",
|
ignoreWhitespace: true,
|
||||||
expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
|
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.Paging.ExternalDiffCommand = s.extDiffCmd
|
userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd
|
||||||
appState := &config.AppState{}
|
appState := &config.AppState{}
|
||||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||||
appState.DiffContextSize = s.contextSize
|
appState.DiffContextSize = s.contextSize
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
|
|
||||||
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
|
||||||
repoPaths := RepoPaths{
|
repoPaths := RepoPaths{
|
||||||
@@ -283,10 +344,9 @@ func TestGetCommitMsg(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{
|
instance := buildCommitCommands(commonDeps{
|
||||||
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "--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,14 +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{"log", "--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{"log", "--format=%B", "--max-count=1", "sha3"}, `use generics to DRY up context code`, nil),
|
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),
|
||||||
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)
|
||||||
@@ -323,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})
|
||||||
|
|
||||||
@@ -333,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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func (self *ConfigCommands) ConfiguredPager() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ConfigCommands) GetPager(width int) string {
|
func (self *ConfigCommands) GetPager(width int) string {
|
||||||
useConfig := self.UserConfig.Git.Paging.UseConfig
|
useConfig := self.UserConfig().Git.Paging.UseConfig
|
||||||
if useConfig {
|
if useConfig {
|
||||||
pager := self.ConfiguredPager()
|
pager := self.ConfiguredPager()
|
||||||
return strings.Split(pager, "| less")[0]
|
return strings.Split(pager, "| less")[0]
|
||||||
@@ -53,14 +53,14 @@ func (self *ConfigCommands) GetPager(width int) string {
|
|||||||
"columnWidth": strconv.Itoa(width/2 - 6),
|
"columnWidth": strconv.Itoa(width/2 - 6),
|
||||||
}
|
}
|
||||||
|
|
||||||
pagerTemplate := string(self.UserConfig.Git.Paging.Pager)
|
pagerTemplate := string(self.UserConfig().Git.Paging.Pager)
|
||||||
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
|
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsingGpg tells us whether the user has gpg enabled so that we can know
|
// UsingGpg tells us whether the user has gpg enabled so that we can know
|
||||||
// whether we need to run a subprocess to allow them to enter their password
|
// whether we need to run a subprocess to allow them to enter their password
|
||||||
func (self *ConfigCommands) UsingGpg() bool {
|
func (self *ConfigCommands) UsingGpg() bool {
|
||||||
overrideGpg := self.UserConfig.Git.OverrideGpg
|
overrideGpg := self.UserConfig().Git.OverrideGpg
|
||||||
if overrideGpg {
|
if overrideGpg {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ func buildGitCommon(deps commonDeps) *GitCommon {
|
|||||||
}
|
}
|
||||||
gitCommon.cmd = cmd
|
gitCommon.cmd = cmd
|
||||||
|
|
||||||
gitCommon.Common.UserConfig = deps.userConfig
|
gitCommon.Common.SetUserConfig(deps.userConfig)
|
||||||
if gitCommon.Common.UserConfig == nil {
|
if gitCommon.Common.UserConfig() == nil {
|
||||||
gitCommon.Common.UserConfig = config.GetDefaultConfig()
|
gitCommon.Common.SetUserConfig(config.GetDefaultConfig())
|
||||||
}
|
}
|
||||||
|
|
||||||
gitCommon.version = deps.gitVersion
|
gitCommon.version = deps.gitVersion
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -12,36 +16,43 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is for generating diffs to be shown in the UI (e.g. rendering a range
|
||||||
|
// diff to the main view). It uses a custom pager if one is configured.
|
||||||
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
func (self *DiffCommands) DiffCmdObj(diffArgs []string) oscommands.ICmdObj {
|
||||||
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
|
useExtDiff := extDiffCmd != ""
|
||||||
|
ignoreWhitespace := self.AppState.IgnoreWhitespaceInDiffView
|
||||||
|
|
||||||
return self.cmd.New(
|
return self.cmd.New(
|
||||||
NewGitCmd("diff").
|
NewGitCmd("diff").
|
||||||
Arg("--submodule", "--no-ext-diff", "--color").
|
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)).
|
||||||
|
ArgIf(ignoreWhitespace, "--ignore-all-space").
|
||||||
|
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||||
Arg(diffArgs...).
|
Arg(diffArgs...).
|
||||||
Dir(self.repoPaths.worktreePath).
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv(),
|
ToArgv(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DiffCommands) internalDiffCmdObj(diffArgs ...string) *GitCommandBuilder {
|
// This is a basic generic diff command that can be used for any diff operation
|
||||||
return NewGitCmd("diff").
|
// (e.g. copying a diff to the clipboard). It will not use a custom pager, and
|
||||||
Arg("--no-ext-diff", "--no-color").
|
// does not use user configs such as ignore whitespace.
|
||||||
Arg(diffArgs...).
|
// If you want to diff specific refs (one or two), you need to add them yourself
|
||||||
Dir(self.repoPaths.worktreePath)
|
// in additionalArgs; it is recommended to also pass `--` after that. If you
|
||||||
}
|
// want to restrict the diff to specific paths, pass them in additionalArgs
|
||||||
|
// after the `--`.
|
||||||
func (self *DiffCommands) GetPathDiff(path string, staged bool) (string, error) {
|
func (self *DiffCommands) GetDiff(staged bool, additionalArgs ...string) (string, error) {
|
||||||
return self.cmd.New(
|
return self.cmd.New(
|
||||||
self.internalDiffCmdObj().
|
NewGitCmd("diff").
|
||||||
ArgIf(staged, "--staged").
|
Config("diff.noprefix=false").
|
||||||
Arg(path).
|
Arg("--no-ext-diff", "--no-color").
|
||||||
ToArgv(),
|
|
||||||
).RunWithOutput()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *DiffCommands) GetAllDiff(staged bool) (string, error) {
|
|
||||||
return self.cmd.New(
|
|
||||||
self.internalDiffCmdObj().
|
|
||||||
ArgIf(staged, "--staged").
|
ArgIf(staged, "--staged").
|
||||||
|
Dir(self.repoPaths.worktreePath).
|
||||||
|
Arg(additionalArgs...).
|
||||||
ToArgv(),
|
ToArgv(),
|
||||||
).RunWithOutput()
|
).RunWithOutput()
|
||||||
}
|
}
|
||||||
@@ -87,6 +98,7 @@ func (self *DiffCommands) OpenDiffToolCmdObj(opts DiffToolCmdOptions) oscommands
|
|||||||
func (self *DiffCommands) DiffIndexCmdObj(diffArgs ...string) oscommands.ICmdObj {
|
func (self *DiffCommands) DiffIndexCmdObj(diffArgs ...string) oscommands.ICmdObj {
|
||||||
return self.cmd.New(
|
return self.cmd.New(
|
||||||
NewGitCmd("diff-index").
|
NewGitCmd("diff-index").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
Arg("--submodule", "--no-ext-diff", "--no-color", "--patch").
|
Arg("--submodule", "--no-ext-diff", "--no-color", "--patch").
|
||||||
Arg(diffArgs...).ToArgv(),
|
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 {
|
||||||
@@ -30,7 +31,7 @@ func (self *FileCommands) Cat(fileName string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) {
|
func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (string, error) {
|
||||||
editor := self.UserConfig.OS.EditCommand
|
editor := self.UserConfig().OS.EditCommand
|
||||||
|
|
||||||
if editor == "" {
|
if editor == "" {
|
||||||
editor = self.config.GetCoreEditor()
|
editor = self.config.GetCoreEditor()
|
||||||
@@ -59,7 +60,7 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (
|
|||||||
"line": strconv.Itoa(lineNumber),
|
"line": strconv.Itoa(lineNumber),
|
||||||
}
|
}
|
||||||
|
|
||||||
editCmdTemplate := self.UserConfig.OS.EditCommandTemplate
|
editCmdTemplate := self.UserConfig().OS.EditCommandTemplate
|
||||||
if len(editCmdTemplate) == 0 {
|
if len(editCmdTemplate) == 0 {
|
||||||
switch editor {
|
switch editor {
|
||||||
case "emacs", "nano", "vi", "vim", "nvim":
|
case "emacs", "nano", "vi", "vim", "nvim":
|
||||||
@@ -75,18 +76,21 @@ 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, suspend := 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)
|
||||||
@@ -95,13 +99,13 @@ func (self *FileCommands) GetEditCmdStr(filename string) (string, bool) {
|
|||||||
|
|
||||||
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
|
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (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.EditAtLine == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
if self.UserConfig().OS.EditAtLine == "" && self.UserConfig().OS.EditCommandTemplate != "" {
|
||||||
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
||||||
return cmdStr, true
|
return cmdStr, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template, suspend := 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),
|
||||||
@@ -114,13 +118,13 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (
|
|||||||
|
|
||||||
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
|
||||||
// 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.EditAtLineAndWait == "" && self.UserConfig.OS.EditCommandTemplate != "" {
|
if self.UserConfig().OS.EditAtLineAndWait == "" && self.UserConfig().OS.EditCommandTemplate != "" {
|
||||||
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
if cmdStr, err := self.GetEditCmdStrLegacy(filename, lineNumber); err == nil {
|
||||||
return cmdStr
|
return cmdStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
|
||||||
|
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"filename": self.cmd.Quote(filename),
|
"filename": self.cmd.Quote(filename),
|
||||||
@@ -132,7 +136,7 @@ func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
|
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
|
||||||
template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
|
template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
|
||||||
|
|
||||||
templateValues := map[string]string{
|
templateValues := map[string]string{
|
||||||
"dir": self.cmd.Quote(path),
|
"dir": self.cmd.Quote(path),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@@ -31,13 +32,17 @@ func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config F
|
|||||||
|
|
||||||
type GetStatusFileOptions struct {
|
type GetStatusFileOptions struct {
|
||||||
NoRenames bool
|
NoRenames bool
|
||||||
|
// If true, we'll show untracked files even if the user has set the config to hide them.
|
||||||
|
// This is useful for users with bare repos for dotfiles who default to hiding untracked files,
|
||||||
|
// but want to occasionally see them to `git add` a new file.
|
||||||
|
ForceShowUntracked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
|
func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
|
||||||
// check if config wants us ignoring untracked files
|
// check if config wants us ignoring untracked files
|
||||||
untrackedFilesSetting := self.config.GetShowUntrackedFiles()
|
untrackedFilesSetting := self.config.GetShowUntrackedFiles()
|
||||||
|
|
||||||
if untrackedFilesSetting == "" {
|
if opts.ForceShowUntracked || untrackedFilesSetting == "" {
|
||||||
untrackedFilesSetting = "all"
|
untrackedFilesSetting = "all"
|
||||||
}
|
}
|
||||||
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
|
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
|
||||||
@@ -48,6 +53,14 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
|||||||
}
|
}
|
||||||
files := []*models.File{}
|
files := []*models.File{}
|
||||||
|
|
||||||
|
fileDiffs := map[string]FileDiff{}
|
||||||
|
if self.GitCommon.Common.UserConfig().Gui.ShowNumstatInFilesView {
|
||||||
|
fileDiffs, err = self.getFileDiffs()
|
||||||
|
if err != nil {
|
||||||
|
self.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, status := range statuses {
|
for _, status := range statuses {
|
||||||
if strings.HasPrefix(status.StatusString, "warning") {
|
if strings.HasPrefix(status.StatusString, "warning") {
|
||||||
self.Log.Warningf("warning when calling git status: %s", status.StatusString)
|
self.Log.Warningf("warning when calling git status: %s", status.StatusString)
|
||||||
@@ -60,6 +73,11 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
|||||||
DisplayString: status.StatusString,
|
DisplayString: status.StatusString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if diff, ok := fileDiffs[status.Name]; ok {
|
||||||
|
file.LinesAdded = diff.LinesAdded
|
||||||
|
file.LinesDeleted = diff.LinesDeleted
|
||||||
|
}
|
||||||
|
|
||||||
models.SetStatusFields(file, status.Change)
|
models.SetStatusFields(file, status.Change)
|
||||||
files = append(files, file)
|
files = append(files, file)
|
||||||
}
|
}
|
||||||
@@ -87,6 +105,45 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
|
|||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileDiff struct {
|
||||||
|
LinesAdded int
|
||||||
|
LinesDeleted int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fileLoader *FileLoader) getFileDiffs() (map[string]FileDiff, error) {
|
||||||
|
diffs, err := fileLoader.gitDiffNumStat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
splitLines := strings.Split(diffs, "\x00")
|
||||||
|
|
||||||
|
fileDiffs := map[string]FileDiff{}
|
||||||
|
for _, line := range splitLines {
|
||||||
|
splitLine := strings.Split(line, "\t")
|
||||||
|
if len(splitLine) != 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
linesAdded, err := strconv.Atoi(splitLine[0])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
linesDeleted, err := strconv.Atoi(splitLine[1])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := splitLine[2]
|
||||||
|
fileDiffs[fileName] = FileDiff{
|
||||||
|
LinesAdded: linesAdded,
|
||||||
|
LinesDeleted: linesDeleted,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileDiffs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GitStatus returns the file status of the repo
|
// GitStatus returns the file status of the repo
|
||||||
type GitStatusOptions struct {
|
type GitStatusOptions struct {
|
||||||
NoRenames bool
|
NoRenames bool
|
||||||
@@ -100,15 +157,29 @@ type FileStatus struct {
|
|||||||
PreviousName string
|
PreviousName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FileLoader) gitStatus(opts GitStatusOptions) ([]FileStatus, error) {
|
func (fileLoader *FileLoader) gitDiffNumStat() (string, error) {
|
||||||
|
return fileLoader.cmd.New(
|
||||||
|
NewGitCmd("diff").
|
||||||
|
Arg("--numstat").
|
||||||
|
Arg("-z").
|
||||||
|
Arg("HEAD").
|
||||||
|
ToArgv(),
|
||||||
|
).DontLog().RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
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,31 +5,41 @@ 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/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
|
||||||
|
showNumstatInFilesView bool
|
||||||
|
expectedFiles []*models.File
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
"No files found",
|
testName: "No files found",
|
||||||
oscommands.NewFakeRunner(t).
|
similarityThreshold: 50,
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "", nil),
|
runner: oscommands.NewFakeRunner(t).
|
||||||
[]*models.File{},
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "", nil),
|
||||||
|
expectedFiles: []*models.File{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Several files found",
|
testName: "Several files found",
|
||||||
oscommands.NewFakeRunner(t).
|
similarityThreshold: 50,
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
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,
|
||||||
|
).
|
||||||
|
ExpectGitArgs([]string{"diff", "--numstat", "-z", "HEAD"},
|
||||||
|
"4\t1\tfile1.txt\x001\t0\tfile2.txt\x002\t2\tfile3.txt\x000\t2\tfile4.txt\x002\t2\tfile5.txt",
|
||||||
|
nil,
|
||||||
),
|
),
|
||||||
[]*models.File{
|
showNumstatInFilesView: true,
|
||||||
|
expectedFiles: []*models.File{
|
||||||
{
|
{
|
||||||
Name: "file1.txt",
|
Name: "file1.txt",
|
||||||
HasStagedChanges: true,
|
HasStagedChanges: true,
|
||||||
@@ -41,6 +51,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "MM file1.txt",
|
DisplayString: "MM file1.txt",
|
||||||
ShortStatus: "MM",
|
ShortStatus: "MM",
|
||||||
|
LinesAdded: 4,
|
||||||
|
LinesDeleted: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "file3.txt",
|
Name: "file3.txt",
|
||||||
@@ -53,6 +65,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "A file3.txt",
|
DisplayString: "A file3.txt",
|
||||||
ShortStatus: "A ",
|
ShortStatus: "A ",
|
||||||
|
LinesAdded: 2,
|
||||||
|
LinesDeleted: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "file2.txt",
|
Name: "file2.txt",
|
||||||
@@ -65,6 +79,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "AM file2.txt",
|
DisplayString: "AM file2.txt",
|
||||||
ShortStatus: "AM",
|
ShortStatus: "AM",
|
||||||
|
LinesAdded: 1,
|
||||||
|
LinesDeleted: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "file4.txt",
|
Name: "file4.txt",
|
||||||
@@ -77,6 +93,8 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasInlineMergeConflicts: false,
|
HasInlineMergeConflicts: false,
|
||||||
DisplayString: "?? file4.txt",
|
DisplayString: "?? file4.txt",
|
||||||
ShortStatus: "??",
|
ShortStatus: "??",
|
||||||
|
LinesAdded: 0,
|
||||||
|
LinesDeleted: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "file5.txt",
|
Name: "file5.txt",
|
||||||
@@ -89,14 +107,17 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
HasInlineMergeConflicts: true,
|
HasInlineMergeConflicts: true,
|
||||||
DisplayString: "UU file5.txt",
|
DisplayString: "UU file5.txt",
|
||||||
ShortStatus: "UU",
|
ShortStatus: "UU",
|
||||||
|
LinesAdded: 2,
|
||||||
|
LinesDeleted: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"File with new line char",
|
testName: "File with new line char",
|
||||||
oscommands.NewFakeRunner(t).
|
similarityThreshold: 50,
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "MM a\nb.txt", nil),
|
runner: oscommands.NewFakeRunner(t).
|
||||||
[]*models.File{
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "MM a\nb.txt", nil),
|
||||||
|
expectedFiles: []*models.File{
|
||||||
{
|
{
|
||||||
Name: "a\nb.txt",
|
Name: "a\nb.txt",
|
||||||
HasStagedChanges: true,
|
HasStagedChanges: true,
|
||||||
@@ -112,13 +133,14 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Renamed files",
|
testName: "Renamed files",
|
||||||
oscommands.NewFakeRunner(t).
|
similarityThreshold: 50,
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
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,
|
||||||
),
|
),
|
||||||
[]*models.File{
|
expectedFiles: []*models.File{
|
||||||
{
|
{
|
||||||
Name: "after1.txt",
|
Name: "after1.txt",
|
||||||
PreviousName: "before1.txt",
|
PreviousName: "before1.txt",
|
||||||
@@ -148,13 +170,14 @@ func TestFileGetStatusFiles(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"File with arrow in name",
|
testName: "File with arrow in name",
|
||||||
oscommands.NewFakeRunner(t).
|
similarityThreshold: 50,
|
||||||
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"},
|
||||||
`?? a -> b.txt`,
|
`?? a -> b.txt`,
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
[]*models.File{
|
expectedFiles: []*models.File{
|
||||||
{
|
{
|
||||||
Name: "a -> b.txt",
|
Name: "a -> b.txt",
|
||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
@@ -172,12 +195,20 @@ 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
|
||||||
|
|
||||||
|
userConfig := &config.UserConfig{
|
||||||
|
Gui: config.GuiConfig{
|
||||||
|
ShowNumstatInFilesView: s.showNumstatInFilesView,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
loader := &FileLoader{
|
loader := &FileLoader{
|
||||||
GitCommon: buildGitCommon(commonDeps{}),
|
GitCommon: buildGitCommon(commonDeps{appState: appState, userConfig: userConfig}),
|
||||||
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,9 +177,9 @@ 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
|
||||||
suspend bool
|
suspend bool
|
||||||
@@ -187,13 +187,13 @@ func TestEditFileCmd(t *testing.T) {
|
|||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
filename: "test",
|
filenames: []string{"test"},
|
||||||
osConfig: config.OSConfig{},
|
osConfig: config.OSConfig{},
|
||||||
expectedCmdStr: `vim -- "test"`,
|
expectedCmdStr: `vim -- "test"`,
|
||||||
suspend: true,
|
suspend: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
filename: "test",
|
filenames: []string{"test"},
|
||||||
osConfig: config.OSConfig{
|
osConfig: config.OSConfig{
|
||||||
Edit: "nano {{filename}}",
|
Edit: "nano {{filename}}",
|
||||||
},
|
},
|
||||||
@@ -201,13 +201,21 @@ func TestEditFileCmd(t *testing.T) {
|
|||||||
suspend: 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"`,
|
||||||
suspend: false,
|
suspend: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
filenames: []string{"multiple", "files"},
|
||||||
|
osConfig: config.OSConfig{
|
||||||
|
EditPreset: "sublime",
|
||||||
|
},
|
||||||
|
expectedCmdStr: `subl -- "multiple" "files"`,
|
||||||
|
suspend: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range scenarios {
|
for _, s := range scenarios {
|
||||||
@@ -218,7 +226,7 @@ func TestEditFileCmd(t *testing.T) {
|
|||||||
userConfig: userConfig,
|
userConfig: userConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
cmdStr, suspend := 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.suspend, suspend)
|
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),
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ func (self *GitCommandBuilder) Dir(path string) *GitCommandBuilder {
|
|||||||
return self
|
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
|
// Note, you may prefer to use the Dir method instead of this one
|
||||||
func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
|
func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
|
||||||
// worktree arg comes before the command
|
// worktree arg comes before the command
|
||||||
@@ -68,6 +76,14 @@ func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *GitCommandBuilder) WorktreePathIf(condition bool, path string) *GitCommandBuilder {
|
||||||
|
if condition {
|
||||||
|
return self.Worktree(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
// Note, you may prefer to use the Dir method instead of this one
|
// Note, you may prefer to use the Dir method instead of this one
|
||||||
func (self *GitCommandBuilder) GitDir(path string) *GitCommandBuilder {
|
func (self *GitCommandBuilder) GitDir(path string) *GitCommandBuilder {
|
||||||
// git dir arg comes before the command
|
// git dir arg comes before the command
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package git_commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/common"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/sasha-s/go-deadlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MainBranches struct {
|
||||||
|
c *common.Common
|
||||||
|
// Which of the configured main branches 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
|
||||||
|
|
||||||
|
previousMainBranches []string
|
||||||
|
|
||||||
|
cmd oscommands.ICmdObjBuilder
|
||||||
|
mutex *deadlock.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMainBranches(
|
||||||
|
cmn *common.Common,
|
||||||
|
cmd oscommands.ICmdObjBuilder,
|
||||||
|
) *MainBranches {
|
||||||
|
return &MainBranches{
|
||||||
|
c: cmn,
|
||||||
|
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()
|
||||||
|
|
||||||
|
configuredMainBranches := self.c.UserConfig().Git.MainBranches
|
||||||
|
|
||||||
|
if self.existingMainBranches == nil || !utils.EqualSlices(self.previousMainBranches, configuredMainBranches) {
|
||||||
|
self.existingMainBranches = self.determineMainBranches(configuredMainBranches)
|
||||||
|
self.previousMainBranches = configuredMainBranches
|
||||||
|
}
|
||||||
|
|
||||||
|
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(configuredMainBranches []string) []string {
|
||||||
|
var existingBranches []string
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
existingBranches = make([]string, len(configuredMainBranches))
|
||||||
|
|
||||||
|
for i, branchName := range 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
|
||||||
|
}
|
||||||
@@ -4,12 +4,12 @@ import (
|
|||||||
"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/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PatchCommands struct {
|
type PatchCommands struct {
|
||||||
@@ -47,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,
|
||||||
@@ -94,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
|
||||||
}
|
}
|
||||||
@@ -123,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
|
||||||
@@ -157,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()
|
||||||
@@ -172,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
|
||||||
}
|
}
|
||||||
@@ -219,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,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()
|
||||||
}
|
}
|
||||||
@@ -282,7 +282,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(
|
|||||||
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
|
||||||
}
|
}
|
||||||
@@ -321,7 +321,11 @@ func (self *PatchCommands) PullPatchIntoNewCommit(
|
|||||||
// 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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +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/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,9 +35,8 @@ func NewRebaseCommands(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
|
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
|
||||||
if models.IsHeadCommit(commits, index) {
|
if self.config.UsingGpg() {
|
||||||
// we've selected the top commit so no rebase is required
|
return errors.New(self.Tr.DisabledForGPG)
|
||||||
return self.commit.RewordLastCommit(summary, description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
|
||||||
@@ -46,7 +45,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, su
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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(summary, description)
|
err = self.commit.RewordLastCommit(summary, description).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -56,79 +55,84 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, su
|
|||||||
|
|
||||||
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) AddCommitCoAuthor(commits []*models.Commit, index int, value string) error {
|
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, value string) error {
|
||||||
return self.GenericAmend(commits, index, func() error {
|
return self.GenericAmend(commits, start, end, func(commit *models.Commit) error {
|
||||||
return self.commit.AddCoAuthor(commits[index].Sha, value)
|
return self.commit.AddCoAuthor(commit.Hash, value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f func() error) error {
|
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, start, end int, f func(commit *models.Commit) error) error {
|
||||||
if models.IsHeadCommit(commits, index) {
|
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) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
|
func (self *RebaseCommands) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+2)
|
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+2)
|
||||||
|
|
||||||
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
return commit.Sha
|
return commit.Hash
|
||||||
})
|
})
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseHashOrRoot: baseHashOrRoot,
|
||||||
instruction: daemon.NewMoveTodosDownInstruction(shas),
|
instruction: daemon.NewMoveTodosDownInstruction(hashes),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
|
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+1)
|
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+1)
|
||||||
|
|
||||||
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
|
||||||
return commit.Sha
|
return commit.Hash
|
||||||
})
|
})
|
||||||
|
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseShaOrRoot,
|
baseHashOrRoot: baseHashOrRoot,
|
||||||
instruction: daemon.NewMoveTodosUpInstruction(shas),
|
instruction: daemon.NewMoveTodosUpInstruction(hashes),
|
||||||
overrideEditor: true,
|
overrideEditor: true,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
@@ -139,19 +143,19 @@ func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx
|
|||||||
baseIndex++
|
baseIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
|
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
|
||||||
|
|
||||||
changes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) daemon.ChangeTodoAction {
|
changes := lo.FilterMap(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) (daemon.ChangeTodoAction, bool) {
|
||||||
return daemon.ChangeTodoAction{
|
return daemon.ChangeTodoAction{
|
||||||
Sha: commit.Sha,
|
Hash: commit.Hash,
|
||||||
NewAction: action,
|
NewAction: action,
|
||||||
}
|
}, !commit.IsMerge()
|
||||||
})
|
})
|
||||||
|
|
||||||
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()
|
||||||
@@ -166,8 +170,8 @@ func (self *RebaseCommands) EditRebase(branchRef string) error {
|
|||||||
)
|
)
|
||||||
self.os.LogCommand(msg, false)
|
self.os.LogCommand(msg, false)
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: branchRef,
|
baseHashOrRoot: branchRef,
|
||||||
instruction: daemon.NewInsertBreakInstruction(),
|
instruction: daemon.NewInsertBreakInstruction(),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,21 +185,21 @@ func (self *RebaseCommands) EditRebaseFromBaseCommit(targetBranchName string, ba
|
|||||||
)
|
)
|
||||||
self.os.LogCommand(msg, false)
|
self.os.LogCommand(msg, false)
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseCommit,
|
baseHashOrRoot: baseCommit,
|
||||||
onto: targetBranchName,
|
onto: targetBranchName,
|
||||||
instruction: daemon.NewInsertBreakInstruction(),
|
instruction: daemon.NewInsertBreakInstruction(),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
|
||||||
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) 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:\n%s", changeTodoStr)
|
return fmt.Sprintf("Changing TODO actions:\n%s", changeTodoStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrepareInteractiveRebaseCommandOpts struct {
|
type PrepareInteractiveRebaseCommandOpts struct {
|
||||||
baseShaOrRoot string
|
baseHashOrRoot string
|
||||||
onto string
|
onto string
|
||||||
instruction daemon.Instruction
|
instruction daemon.Instruction
|
||||||
overrideEditor bool
|
overrideEditor bool
|
||||||
@@ -204,7 +208,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()
|
||||||
|
|
||||||
@@ -216,7 +220,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
|
|||||||
Arg("--no-autosquash").
|
Arg("--no-autosquash").
|
||||||
ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges").
|
ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges").
|
||||||
ArgIf(opts.onto != "", "--onto", opts.onto).
|
ArgIf(opts.onto != "", "--onto", opts.onto).
|
||||||
Arg(opts.baseShaOrRoot).
|
Arg(opts.baseHashOrRoot).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
debug := "FALSE"
|
debug := "FALSE"
|
||||||
@@ -233,7 +237,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(
|
||||||
@@ -250,34 +254,87 @@ 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) getHashOfLastCommitMade() (string, error) {
|
||||||
|
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
||||||
|
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
fixupHash, err := self.getHashOfLastCommitMade()
|
||||||
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
|
||||||
fixupSha, 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, true),
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) MoveFixupCommitDown(commits []*models.Commit, targetCommitIndex int) error {
|
||||||
|
fixupHash, err := self.getHashOfLastCommitMade()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseHashOrRoot: getBaseHashOrRoot(commits, targetCommitIndex+1),
|
||||||
|
overrideEditor: true,
|
||||||
|
instruction: daemon.NewMoveFixupCommitDownInstruction(commits[targetCommitIndex].Hash, fixupHash, false),
|
||||||
|
}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func todoFromCommit(commit *models.Commit) utils.Todo {
|
||||||
|
if commit.Action == todo.UpdateRef {
|
||||||
|
return utils.Todo{Ref: commit.Name}
|
||||||
|
} else {
|
||||||
|
return utils.Todo{Hash: commit.Hash}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the action for the given commits in the git-rebase-todo file
|
// Sets the action for the given commits in the git-rebase-todo file
|
||||||
func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo.TodoCommand) error {
|
func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo.TodoCommand) error {
|
||||||
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
|
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
|
||||||
return utils.TodoChange{
|
return utils.TodoChange{
|
||||||
Sha: commit.Sha,
|
Hash: commit.Hash,
|
||||||
OldAction: commit.Action,
|
|
||||||
NewAction: action,
|
NewAction: action,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -289,39 +346,50 @@ func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) DeleteUpdateRefTodos(commits []*models.Commit) error {
|
||||||
|
todosToDelete := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
|
return todoFromCommit(commit)
|
||||||
|
})
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
|
||||||
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
return utils.Todo{
|
return todoFromCommit(commit)
|
||||||
Sha: commit.Sha,
|
|
||||||
Action: commit.Action,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return utils.MoveTodosDown(fileName, todosToMove, self.config.GetCoreCommentChar())
|
return utils.MoveTodosDown(fileName, todosToMove, true, self.config.GetCoreCommentChar())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
|
func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
|
||||||
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
|
||||||
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
|
||||||
return utils.Todo{
|
return todoFromCommit(commit)
|
||||||
Sha: commit.Sha,
|
|
||||||
Action: commit.Action,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return utils.MoveTodosUp(fileName, todosToMove, self.config.GetCoreCommentChar())
|
return utils.MoveTodosUp(fileName, todosToMove, true, 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))
|
||||||
@@ -332,7 +400,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")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,14 +417,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),
|
||||||
@@ -359,13 +436,13 @@ 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 {
|
func (self *RebaseCommands) RebaseBranchFromBaseCommit(targetBranchName string, baseCommit string) error {
|
||||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
baseShaOrRoot: baseCommit,
|
baseHashOrRoot: baseCommit,
|
||||||
onto: targetBranchName,
|
onto: targetBranchName,
|
||||||
}).Run()
|
}).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,23 +500,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
|
||||||
@@ -452,10 +531,10 @@ 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)
|
||||||
})
|
})
|
||||||
msg := utils.ResolvePlaceholderString(
|
msg := utils.ResolvePlaceholderString(
|
||||||
self.Tr.Log.CherryPickCommits,
|
self.Tr.Log.CherryPickCommits,
|
||||||
@@ -466,8 +545,8 @@ func (self *RebaseCommands) CherryPickCommits(commits []*models.Commit) error {
|
|||||||
self.os.LogCommand(msg, false)
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,15 +564,22 @@ func (self *RebaseCommands) CherryPickCommitsDuringRebase(commits []*models.Comm
|
|||||||
return utils.PrependStrToTodoFile(filePath, []byte(todo))
|
return utils.PrependStrToTodoFile(filePath, []byte(todo))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) DropMergeCommit(commits []*models.Commit, commitIndex int) error {
|
||||||
|
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||||
|
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
|
||||||
|
instruction: daemon.NewDropMergeCommitInstruction(commits[commitIndex].Hash),
|
||||||
|
}).Run()
|
||||||
|
}
|
||||||
|
|
||||||
// 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))
|
||||||
@@ -89,7 +88,6 @@ 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)
|
||||||
})
|
})
|
||||||
@@ -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,15 +141,15 @@ 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).
|
||||||
ExpectGitArgs([]string{"checkout", "HEAD^", "--", "test999.txt"}, "", nil).
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "HEAD^", "--", "test999.txt"}, "", nil).
|
||||||
ExpectGitArgs([]string{"commit", "--amend", "--no-edit", "--allow-empty"}, "", nil).
|
ExpectGitArgs([]string{"commit", "--amend", "--no-edit", "--allow-empty"}, "", nil).
|
||||||
ExpectGitArgs([]string{"rebase", "--continue"}, "", nil),
|
ExpectGitArgs([]string{"rebase", "--continue"}, "", nil),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
@@ -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,6 +31,7 @@ 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()
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 && self.sameReflogCommit(commit, lastReflogCommit) {
|
if lastReflogCommit != nil && self.sameReflogCommit(commit, lastReflogCommit) {
|
||||||
@@ -64,7 +65,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ReflogCommitLoader) sameReflogCommit(a *models.Commit, b *models.Commit) bool {
|
func (self *ReflogCommitLoader) sameReflogCommit(a *models.Commit, b *models.Commit) bool {
|
||||||
return a.Sha == b.Sha && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
|
return a.Hash == b.Hash && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
|
func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
|
||||||
@@ -82,7 +83,7 @@ func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &models.Commit{
|
return &models.Commit{
|
||||||
Sha: fields[0],
|
Hash: fields[0],
|
||||||
Name: fields[2],
|
Name: fields[2],
|
||||||
UnixTimestamp: int64(unixTimestamp),
|
UnixTimestamp: int64(unixTimestamp),
|
||||||
Status: models.StatusReflog,
|
Status: models.StatusReflog,
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -49,9 +49,10 @@ func (self *RemoteCommands) UpdateRemoteUrl(remoteName string, updatedUrl string
|
|||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName string, branchName string) error {
|
func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName string, branchNames []string) error {
|
||||||
cmdArgs := NewGitCmd("push").
|
cmdArgs := NewGitCmd("push").
|
||||||
Arg(remoteName, "--delete", branchName).
|
Arg(remoteName, "--delete").
|
||||||
|
Arg(branchNames...).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
ioFs "io/fs"
|
ioFs "io/fs"
|
||||||
"path"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ type RepoPaths struct {
|
|||||||
repoPath string
|
repoPath string
|
||||||
repoGitDirPath string
|
repoGitDirPath string
|
||||||
repoName string
|
repoName string
|
||||||
|
isBareRepo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
|
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
|
||||||
@@ -54,14 +55,19 @@ func (self *RepoPaths) RepoName() string {
|
|||||||
return self.repoName
|
return self.repoName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *RepoPaths) IsBareRepo() bool {
|
||||||
|
return self.isBareRepo
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the repo paths for a typical repo
|
// Returns the repo paths for a typical repo
|
||||||
func MockRepoPaths(currentPath string) *RepoPaths {
|
func MockRepoPaths(currentPath string) *RepoPaths {
|
||||||
return &RepoPaths{
|
return &RepoPaths{
|
||||||
worktreePath: currentPath,
|
worktreePath: currentPath,
|
||||||
worktreeGitDirPath: path.Join(currentPath, ".git"),
|
worktreeGitDirPath: filepath.Join(currentPath, ".git"),
|
||||||
repoPath: currentPath,
|
repoPath: currentPath,
|
||||||
repoGitDirPath: path.Join(currentPath, ".git"),
|
repoGitDirPath: filepath.Join(currentPath, ".git"),
|
||||||
repoName: "lazygit",
|
repoName: "lazygit",
|
||||||
|
isBareRepo: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +75,19 @@ func GetRepoPaths(
|
|||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
version *GitVersion,
|
version *GitVersion,
|
||||||
) (*RepoPaths, error) {
|
) (*RepoPaths, error) {
|
||||||
gitDirOutput, err := callGitRevParse(cmd, version, "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -84,21 +102,22 @@ func GetRepoPaths(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isBareRepo := gitDirResults[3] == "true"
|
||||||
|
|
||||||
// If we're in a submodule, --show-superproject-working-tree will return
|
// If we're in a submodule, --show-superproject-working-tree will return
|
||||||
// a value, meaning gitDirResults will be length 4. In that case
|
// a value, meaning gitDirResults will be length 5. In that case
|
||||||
// return the worktree path as the repoPath. Otherwise we're in a
|
// 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
|
// normal repo or a worktree so return the parent of the git common
|
||||||
// dir (repoGitDirPath)
|
// dir (repoGitDirPath)
|
||||||
isSubmodule := len(gitDirResults) == 4
|
isSubmodule := len(gitDirResults) == 5
|
||||||
|
|
||||||
var repoPath string
|
var repoPath string
|
||||||
if isSubmodule {
|
if isSubmodule {
|
||||||
repoPath = worktreePath
|
repoPath = worktreePath
|
||||||
} else {
|
} else {
|
||||||
repoPath = path.Dir(repoGitDirPath)
|
repoPath = filepath.Dir(repoGitDirPath)
|
||||||
}
|
}
|
||||||
repoName := path.Base(repoPath)
|
repoName := filepath.Base(repoPath)
|
||||||
|
|
||||||
return &RepoPaths{
|
return &RepoPaths{
|
||||||
worktreePath: worktreePath,
|
worktreePath: worktreePath,
|
||||||
@@ -106,17 +125,10 @@ func GetRepoPaths(
|
|||||||
repoPath: repoPath,
|
repoPath: repoPath,
|
||||||
repoGitDirPath: repoGitDirPath,
|
repoGitDirPath: repoGitDirPath,
|
||||||
repoName: repoName,
|
repoName: repoName,
|
||||||
|
isBareRepo: isBareRepo,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func callGitRevParse(
|
|
||||||
cmd oscommands.ICmdObjBuilder,
|
|
||||||
version *GitVersion,
|
|
||||||
gitRevArgs ...string,
|
|
||||||
) (string, error) {
|
|
||||||
return callGitRevParseWithDir(cmd, version, "", gitRevArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func callGitRevParseWithDir(
|
func callGitRevParseWithDir(
|
||||||
cmd oscommands.ICmdObjBuilder,
|
cmd oscommands.ICmdObjBuilder,
|
||||||
version *GitVersion,
|
version *GitVersion,
|
||||||
@@ -141,7 +153,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
result := []string{}
|
result := []string{}
|
||||||
// For each directory in this path we're going to cat the `gitdir` file and append its contents to our result
|
// 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.
|
// That file points us to the `.git` file in the worktree.
|
||||||
worktreeGitDirsPath := path.Join(repoGitDirPath, "worktrees")
|
worktreeGitDirsPath := filepath.Join(repoGitDirPath, "worktrees")
|
||||||
|
|
||||||
// ensure the directory exists
|
// ensure the directory exists
|
||||||
_, err := fs.Stat(worktreeGitDirsPath)
|
_, err := fs.Stat(worktreeGitDirsPath)
|
||||||
@@ -158,7 +170,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gitDirPath := path.Join(currPath, "gitdir")
|
gitDirPath := filepath.Join(currPath, "gitdir")
|
||||||
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
|
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ignoring error
|
// ignoring error
|
||||||
@@ -166,7 +178,7 @@ func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
|
|||||||
}
|
}
|
||||||
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
|
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
|
||||||
// removing the .git part
|
// removing the .git part
|
||||||
worktreeDir := path.Dir(trimmedGitDir)
|
worktreeDir := filepath.Dir(trimmedGitDir)
|
||||||
result = append(result, worktreeDir)
|
result = append(result, worktreeDir)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/samber/lo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,63 +31,152 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
Name: "typical case",
|
Name: "typical case",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
// setup for main worktree
|
// setup for main worktree
|
||||||
expectedOutput := []string{
|
mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{
|
||||||
|
// --show-toplevel
|
||||||
|
`C:\path\to\repo`,
|
||||||
|
// --git-dir
|
||||||
|
`C:\path\to\repo\.git`,
|
||||||
|
// --git-common-dir
|
||||||
|
`C:\path\to\repo\.git`,
|
||||||
|
// --is-bare-repository
|
||||||
|
"false",
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
}, []string{
|
||||||
// --show-toplevel
|
// --show-toplevel
|
||||||
"/path/to/repo",
|
"/path/to/repo",
|
||||||
// --git-dir
|
// --git-dir
|
||||||
"/path/to/repo/.git",
|
"/path/to/repo/.git",
|
||||||
// --git-common-dir
|
// --git-common-dir
|
||||||
"/path/to/repo/.git",
|
"/path/to/repo/.git",
|
||||||
|
// --is-bare-repository
|
||||||
|
"false",
|
||||||
// --show-superproject-working-tree
|
// --show-superproject-working-tree
|
||||||
}
|
})
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
strings.Join(expectedOutput, "\n"),
|
strings.Join(mockOutput, "\n"),
|
||||||
nil)
|
nil)
|
||||||
},
|
},
|
||||||
Path: "/path/to/repo",
|
Path: "/path/to/repo",
|
||||||
Expected: &RepoPaths{
|
Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{
|
||||||
|
worktreePath: `C:\path\to\repo`,
|
||||||
|
worktreeGitDirPath: `C:\path\to\repo\.git`,
|
||||||
|
repoPath: `C:\path\to\repo`,
|
||||||
|
repoGitDirPath: `C:\path\to\repo\.git`,
|
||||||
|
repoName: `repo`,
|
||||||
|
isBareRepo: false,
|
||||||
|
}, &RepoPaths{
|
||||||
worktreePath: "/path/to/repo",
|
worktreePath: "/path/to/repo",
|
||||||
worktreeGitDirPath: "/path/to/repo/.git",
|
worktreeGitDirPath: "/path/to/repo/.git",
|
||||||
repoPath: "/path/to/repo",
|
repoPath: "/path/to/repo",
|
||||||
repoGitDirPath: "/path/to/repo/.git",
|
repoGitDirPath: "/path/to/repo/.git",
|
||||||
repoName: "repo",
|
repoName: "repo",
|
||||||
|
isBareRepo: false,
|
||||||
|
}),
|
||||||
|
Err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "bare repo",
|
||||||
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
|
// setup for main worktree
|
||||||
|
mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{
|
||||||
|
// --show-toplevel
|
||||||
|
`C:\path\to\repo`,
|
||||||
|
// --git-dir
|
||||||
|
`C:\path\to\bare_repo\bare.git`,
|
||||||
|
// --git-common-dir
|
||||||
|
`C:\path\to\bare_repo\bare.git`,
|
||||||
|
// --is-bare-repository
|
||||||
|
`true`,
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
}, []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(mockOutput, "\n"),
|
||||||
|
nil)
|
||||||
},
|
},
|
||||||
|
Path: "/path/to/repo",
|
||||||
|
Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{
|
||||||
|
worktreePath: `C:\path\to\repo`,
|
||||||
|
worktreeGitDirPath: `C:\path\to\bare_repo\bare.git`,
|
||||||
|
repoPath: `C:\path\to\bare_repo`,
|
||||||
|
repoGitDirPath: `C:\path\to\bare_repo\bare.git`,
|
||||||
|
repoName: `bare_repo`,
|
||||||
|
isBareRepo: true,
|
||||||
|
}, &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,
|
Err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "submodule",
|
Name: "submodule",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
expectedOutput := []string{
|
mockOutput := lo.Ternary(runtime.GOOS == "windows", []string{
|
||||||
|
// --show-toplevel
|
||||||
|
`C:\path\to\repo\submodule1`,
|
||||||
|
// --git-dir
|
||||||
|
`C:\path\to\repo\.git\modules\submodule1`,
|
||||||
|
// --git-common-dir
|
||||||
|
`C:\path\to\repo\.git\modules\submodule1`,
|
||||||
|
// --is-bare-repository
|
||||||
|
`false`,
|
||||||
|
// --show-superproject-working-tree
|
||||||
|
`C:\path\to\repo`,
|
||||||
|
}, []string{
|
||||||
// --show-toplevel
|
// --show-toplevel
|
||||||
"/path/to/repo/submodule1",
|
"/path/to/repo/submodule1",
|
||||||
// --git-dir
|
// --git-dir
|
||||||
"/path/to/repo/.git/modules/submodule1",
|
"/path/to/repo/.git/modules/submodule1",
|
||||||
// --git-common-dir
|
// --git-common-dir
|
||||||
"/path/to/repo/.git/modules/submodule1",
|
"/path/to/repo/.git/modules/submodule1",
|
||||||
|
// --is-bare-repository
|
||||||
|
"false",
|
||||||
// --show-superproject-working-tree
|
// --show-superproject-working-tree
|
||||||
"/path/to/repo",
|
"/path/to/repo",
|
||||||
}
|
})
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
|
||||||
strings.Join(expectedOutput, "\n"),
|
strings.Join(mockOutput, "\n"),
|
||||||
nil)
|
nil)
|
||||||
},
|
},
|
||||||
Path: "/path/to/repo/submodule1",
|
Path: "/path/to/repo/submodule1",
|
||||||
Expected: &RepoPaths{
|
Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{
|
||||||
|
worktreePath: `C:\path\to\repo\submodule1`,
|
||||||
|
worktreeGitDirPath: `C:\path\to\repo\.git\modules\submodule1`,
|
||||||
|
repoPath: `C:\path\to\repo\submodule1`,
|
||||||
|
repoGitDirPath: `C:\path\to\repo\.git\modules\submodule1`,
|
||||||
|
repoName: `submodule1`,
|
||||||
|
isBareRepo: false,
|
||||||
|
}, &RepoPaths{
|
||||||
worktreePath: "/path/to/repo/submodule1",
|
worktreePath: "/path/to/repo/submodule1",
|
||||||
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
repoPath: "/path/to/repo/submodule1",
|
repoPath: "/path/to/repo/submodule1",
|
||||||
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
|
||||||
repoName: "submodule1",
|
repoName: "submodule1",
|
||||||
},
|
isBareRepo: false,
|
||||||
|
}),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "git rev-parse returns an error",
|
Name: "git rev-parse returns an error",
|
||||||
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
|
||||||
runner.ExpectGitArgs(
|
runner.ExpectGitArgs(
|
||||||
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--show-superproject-working-tree"),
|
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"))
|
errors.New("fatal: invalid gitfile format: /path/to/repo/worktree2/.git"))
|
||||||
},
|
},
|
||||||
@@ -94,14 +185,13 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
Err: func(getRevParseArgs argFn) error {
|
Err: func(getRevParseArgs argFn) error {
|
||||||
args := strings.Join(getRevParseArgs(), " ")
|
args := strings.Join(getRevParseArgs(), " ")
|
||||||
return errors.New(
|
return errors.New(
|
||||||
fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args),
|
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 {
|
for _, s := range scenarios {
|
||||||
s := s
|
|
||||||
t.Run(s.Name, func(t *testing.T) {
|
t.Run(s.Name, func(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t)
|
runner := oscommands.NewFakeRunner(t)
|
||||||
cmd := oscommands.NewDummyCmdObjBuilder(runner)
|
cmd := oscommands.NewDummyCmdObjBuilder(runner)
|
||||||
@@ -121,7 +211,7 @@ func TestGetRepoPaths(t *testing.T) {
|
|||||||
// prepare the filesystem for the scenario
|
// prepare the filesystem for the scenario
|
||||||
s.BeforeFunc(runner, getRevParseArgs)
|
s.BeforeFunc(runner, getRevParseArgs)
|
||||||
|
|
||||||
repoPaths, err := GetRepoPaths(cmd, version)
|
repoPaths, err := GetRepoPathsForDir("", cmd, version)
|
||||||
|
|
||||||
// check the error and the paths
|
// check the error and the paths
|
||||||
if s.Err != nil {
|
if s.Err != nil {
|
||||||
|
|||||||
@@ -60,33 +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) oscommands.ICmdObj {
|
func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
|
||||||
|
// "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason
|
||||||
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("-u").
|
||||||
|
Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)).
|
||||||
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||||
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--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).
|
Dir(self.repoPaths.worktreePath).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
@@ -121,9 +124,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(),
|
||||||
@@ -179,7 +195,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
|
||||||
}
|
}
|
||||||
@@ -188,7 +204,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,88 +55,99 @@ 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 uint64
|
||||||
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", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "stash@{5}"},
|
ignoreWhitespace: false,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--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", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "stash@{5}"},
|
ignoreWhitespace: false,
|
||||||
|
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--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", "-C", "/path/to/worktree", "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", "-u", "--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", "-u", "--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()
|
||||||
appState := &config.AppState{}
|
appState := &config.AppState{}
|
||||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||||
appState.DiffContextSize = s.contextSize
|
appState.DiffContextSize = s.contextSize
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
repoPaths := RepoPaths{
|
repoPaths := RepoPaths{
|
||||||
worktreePath: "/path/to/worktree",
|
worktreePath: "/path/to/worktree",
|
||||||
}
|
}
|
||||||
@@ -153,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
|
||||||
}
|
}
|
||||||
@@ -164,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"},
|
||||||
},
|
},
|
||||||
@@ -173,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})
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"os"
|
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,20 +47,8 @@ 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) {
|
|
||||||
res, err := osCommand.Cmd.New(
|
|
||||||
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
|
|
||||||
return strconv.ParseBool(strings.TrimSpace(res))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StatusCommands) IsInNormalRebase() (bool, error) {
|
func (self *StatusCommands) IsInNormalRebase() (bool, error) {
|
||||||
|
|||||||
@@ -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").
|
||||||
Dir(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(),
|
||||||
@@ -141,7 +170,7 @@ func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
|
|||||||
|
|
||||||
// We may in fact want to use the repo's git dir path but git docs say not to
|
// We may in fact want to use the repo's git dir path but git docs say not to
|
||||||
// mix submodules and worktrees anyway.
|
// mix submodules and worktrees anyway.
|
||||||
return os.RemoveAll(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "modules", submodule.Path))
|
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 {
|
||||||
@@ -158,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()
|
||||||
|
|
||||||
@@ -170,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 {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package git_commands
|
package git_commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
@@ -19,6 +21,8 @@ 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
|
||||||
|
CurrentBranch string
|
||||||
UpstreamRemote string
|
UpstreamRemote string
|
||||||
UpstreamBranch string
|
UpstreamBranch string
|
||||||
SetUpstream bool
|
SetUpstream bool
|
||||||
@@ -30,10 +34,11 @@ 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 != "", fmt.Sprintf("refs/heads/%s:%s", opts.CurrentBranch, opts.UpstreamBranch)).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
|
cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
|
||||||
@@ -58,7 +63,7 @@ func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
|
func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
|
||||||
cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()
|
cmdArgs := self.fetchCommandBuilder(self.UserConfig().Git.FetchAll).ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs)
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
cmdObj.PromptOnCredentialRequest(task)
|
cmdObj.PromptOnCredentialRequest(task)
|
||||||
@@ -70,7 +75,7 @@ func (self *SyncCommands) Fetch(task gocui.Task) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
|
||||||
cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()
|
cmdArgs := self.fetchCommandBuilder(self.UserConfig().Git.FetchAll).ToArgv()
|
||||||
|
|
||||||
cmdObj := self.cmd.New(cmdArgs)
|
cmdObj := self.cmd.New(cmdArgs)
|
||||||
cmdObj.DontLog().FailOnCredentialRequest()
|
cmdObj.DontLog().FailOnCredentialRequest()
|
||||||
@@ -86,6 +91,7 @@ type PullOptions struct {
|
|||||||
BranchName string
|
BranchName string
|
||||||
FastForwardOnly bool
|
FastForwardOnly bool
|
||||||
WorktreeGitDir string
|
WorktreeGitDir string
|
||||||
|
WorktreePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
||||||
@@ -93,8 +99,9 @@ func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
|
|||||||
Arg("--no-edit").
|
Arg("--no-edit").
|
||||||
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 != "", "refs/heads/"+opts.BranchName).
|
||||||
GitDirIf(opts.WorktreeGitDir != "", opts.WorktreeGitDir).
|
GitDirIf(opts.WorktreeGitDir != "", opts.WorktreeGitDir).
|
||||||
|
WorktreePathIf(opts.WorktreePath != "", opts.WorktreePath).
|
||||||
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
|
||||||
@@ -110,7 +117,7 @@ func (self *SyncCommands) FastForward(
|
|||||||
) error {
|
) error {
|
||||||
cmdArgs := self.fetchCommandBuilder(false).
|
cmdArgs := self.fetchCommandBuilder(false).
|
||||||
Arg(remoteName).
|
Arg(remoteName).
|
||||||
Arg(remoteBranchName + ":" + branchName).
|
Arg("refs/heads/" + remoteBranchName + ":" + branchName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||||
|
|||||||
@@ -18,62 +18,73 @@ 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,
|
||||||
|
CurrentBranch: "master",
|
||||||
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", "refs/heads/master: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,
|
||||||
|
CurrentBranch: "master-local",
|
||||||
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", "refs/heads/master-local: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,
|
||||||
|
CurrentBranch: "master",
|
||||||
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", "refs/heads/master: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 +97,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,10 +134,9 @@ 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
|
||||||
task := gocui.NewFakeTask()
|
task := gocui.NewFakeTask()
|
||||||
s.test(instance.FetchCmdObj(task))
|
s.test(instance.FetchCmdObj(task))
|
||||||
})
|
})
|
||||||
@@ -163,10 +172,9 @@ 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
|
||||||
s.test(instance.FetchBackgroundCmdObj())
|
s.test(instance.FetchBackgroundCmdObj())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package git_commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
@@ -108,6 +109,10 @@ func (self *WorkingTreeCommands) BeforeAndAfterFileForRename(file *models.File)
|
|||||||
return beforeFile, afterFile, nil
|
return beforeFile, afterFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newCheckoutCommand() *GitCommandBuilder {
|
||||||
|
return NewGitCmd("checkout").Config(fmt.Sprintf("core.hooksPath=%s", os.DevNull))
|
||||||
|
}
|
||||||
|
|
||||||
// DiscardAllFileChanges directly
|
// DiscardAllFileChanges directly
|
||||||
func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error {
|
func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error {
|
||||||
if file.IsRename() {
|
if file.IsRename() {
|
||||||
@@ -129,7 +134,7 @@ func (self *WorkingTreeCommands) DiscardAllFileChanges(file *models.File) error
|
|||||||
|
|
||||||
if file.ShortStatus == "AA" {
|
if file.ShortStatus == "AA" {
|
||||||
if err := self.cmd.New(
|
if err := self.cmd.New(
|
||||||
NewGitCmd("checkout").Arg("--ours", "--", file.Name).ToArgv(),
|
newCheckoutCommand().Arg("--ours", "--", file.Name).ToArgv(),
|
||||||
).Run(); err != nil {
|
).Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -188,7 +193,7 @@ func (self *WorkingTreeCommands) DiscardUnstagedDirChanges(node IFileNode) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("checkout").Arg("--", node.GetPath()).ToArgv()
|
cmdArgs := newCheckoutCommand().Arg("--", node.GetPath()).ToArgv()
|
||||||
if err := self.cmd.New(cmdArgs).Run(); err != nil {
|
if err := self.cmd.New(cmdArgs).Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -221,7 +226,7 @@ func (self *WorkingTreeCommands) RemoveUntrackedDirFiles(node IFileNode) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeCommands) DiscardUnstagedFileChanges(file *models.File) error {
|
func (self *WorkingTreeCommands) DiscardUnstagedFileChanges(file *models.File) error {
|
||||||
cmdArgs := NewGitCmd("checkout").Arg("--", file.Name).ToArgv()
|
cmdArgs := newCheckoutCommand().Arg("--", file.Name).ToArgv()
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +237,8 @@ func (self *WorkingTreeCommands) Ignore(filename string) error {
|
|||||||
|
|
||||||
// Exclude adds a file to the .git/info/exclude for the repo
|
// Exclude adds a file to the .git/info/exclude for the repo
|
||||||
func (self *WorkingTreeCommands) Exclude(filename string) error {
|
func (self *WorkingTreeCommands) Exclude(filename string) error {
|
||||||
return self.os.AppendLineToFile(".git/info/exclude", filename)
|
excludeFile := filepath.Join(self.repoPaths.repoGitDirPath, "info", "exclude")
|
||||||
|
return self.os.AppendLineToFile(excludeFile, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WorktreeFileDiff returns the diff of a file
|
// WorktreeFileDiff returns the diff of a file
|
||||||
@@ -243,7 +249,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) oscommands.ICmdObj {
|
func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain bool, cached bool) oscommands.ICmdObj {
|
||||||
colorArg := self.UserConfig.Git.Paging.ColorArg
|
colorArg := self.UserConfig().Git.Paging.ColorArg
|
||||||
if plain {
|
if plain {
|
||||||
colorArg = "never"
|
colorArg = "never"
|
||||||
}
|
}
|
||||||
@@ -251,7 +257,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
|
|||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
prevPath := node.GetPreviousPath()
|
prevPath := node.GetPreviousPath()
|
||||||
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile()
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
useExtDiff := extDiffCmd != "" && !plain
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
@@ -261,6 +267,7 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain
|
|||||||
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
Arg(fmt.Sprintf("--unified=%d", contextSize)).
|
||||||
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
Arg(fmt.Sprintf("--color=%s", colorArg)).
|
||||||
ArgIf(!plain && self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
ArgIf(!plain && self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||||
|
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
||||||
ArgIf(cached, "--cached").
|
ArgIf(cached, "--cached").
|
||||||
ArgIf(noIndex, "--no-index").
|
ArgIf(noIndex, "--no-index").
|
||||||
Arg("--").
|
Arg("--").
|
||||||
@@ -282,15 +289,16 @@ func (self *WorkingTreeCommands) ShowFileDiff(from string, to string, reverse bo
|
|||||||
func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reverse bool, fileName string, plain bool) oscommands.ICmdObj {
|
func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reverse bool, fileName string, plain bool) oscommands.ICmdObj {
|
||||||
contextSize := self.AppState.DiffContextSize
|
contextSize := self.AppState.DiffContextSize
|
||||||
|
|
||||||
colorArg := self.UserConfig.Git.Paging.ColorArg
|
colorArg := self.UserConfig().Git.Paging.ColorArg
|
||||||
if plain {
|
if plain {
|
||||||
colorArg = "never"
|
colorArg = "never"
|
||||||
}
|
}
|
||||||
|
|
||||||
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
|
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
|
||||||
useExtDiff := extDiffCmd != "" && !plain
|
useExtDiff := extDiffCmd != "" && !plain
|
||||||
|
|
||||||
cmdArgs := NewGitCmd("diff").
|
cmdArgs := NewGitCmd("diff").
|
||||||
|
Config("diff.noprefix=false").
|
||||||
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
|
||||||
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
|
||||||
Arg("--submodule").
|
Arg("--submodule").
|
||||||
@@ -310,8 +318,8 @@ func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reve
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckoutFile checks out the file for the given commit
|
// CheckoutFile checks out the file for the given commit
|
||||||
func (self *WorkingTreeCommands) CheckoutFile(commitSha, fileName string) error {
|
func (self *WorkingTreeCommands) CheckoutFile(commitHash, fileName string) error {
|
||||||
cmdArgs := NewGitCmd("checkout").Arg(commitSha, "--", fileName).
|
cmdArgs := newCheckoutCommand().Arg(commitHash, "--", fileName).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
@@ -319,7 +327,7 @@ func (self *WorkingTreeCommands) CheckoutFile(commitSha, fileName string) error
|
|||||||
|
|
||||||
// DiscardAnyUnstagedFileChanges discards any unstaged file changes via `git checkout -- .`
|
// DiscardAnyUnstagedFileChanges discards any unstaged file changes via `git checkout -- .`
|
||||||
func (self *WorkingTreeCommands) DiscardAnyUnstagedFileChanges() error {
|
func (self *WorkingTreeCommands) DiscardAnyUnstagedFileChanges() error {
|
||||||
cmdArgs := NewGitCmd("checkout").Arg("--", ".").
|
cmdArgs := newCheckoutCommand().Arg("--", ".").
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|
||||||
return self.cmd.New(cmdArgs).Run()
|
return self.cmd.New(cmdArgs).Run()
|
||||||
@@ -342,7 +350,7 @@ func (self *WorkingTreeCommands) RemoveUntrackedFiles() error {
|
|||||||
|
|
||||||
// ResetAndClean removes all unstaged changes and removes all untracked files
|
// ResetAndClean removes all unstaged changes and removes all untracked files
|
||||||
func (self *WorkingTreeCommands) ResetAndClean() error {
|
func (self *WorkingTreeCommands) ResetAndClean() error {
|
||||||
submoduleConfigs, err := self.submodule.GetConfigs()
|
submoduleConfigs, err := self.submodule.GetConfigs(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -360,7 +368,7 @@ func (self *WorkingTreeCommands) ResetAndClean() error {
|
|||||||
return self.RemoveUntrackedFiles()
|
return self.RemoveUntrackedFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetHardHead runs `git reset --hard`
|
// ResetHard runs `git reset --hard`
|
||||||
func (self *WorkingTreeCommands) ResetHard(ref string) error {
|
func (self *WorkingTreeCommands) ResetHard(ref string) error {
|
||||||
cmdArgs := NewGitCmd("reset").Arg("--hard", ref).
|
cmdArgs := NewGitCmd("reset").Arg("--hard", ref).
|
||||||
ToArgv()
|
ToArgv()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package git_commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
@@ -11,6 +12,8 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var disableHooksFlag = fmt.Sprintf("core.hooksPath=%s", os.DevNull)
|
||||||
|
|
||||||
func TestWorkingTreeStageFile(t *testing.T) {
|
func TestWorkingTreeStageFile(t *testing.T) {
|
||||||
runner := oscommands.NewFakeRunner(t).
|
runner := oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"add", "--", "test.txt"}, "", nil)
|
ExpectGitArgs([]string{"add", "--", "test.txt"}, "", nil)
|
||||||
@@ -61,7 +64,6 @@ func TestWorkingTreeUnstageFile(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.UnStageFile([]string{"test.txt"}, s.reset))
|
s.test(instance.UnStageFile([]string{"test.txt"}, s.reset))
|
||||||
@@ -101,7 +103,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
Added: true,
|
Added: true,
|
||||||
},
|
},
|
||||||
removeFile: func(string) error {
|
removeFile: func(string) error {
|
||||||
return fmt.Errorf("an error occurred when removing file")
|
return errors.New("an error occurred when removing file")
|
||||||
},
|
},
|
||||||
runner: oscommands.NewFakeRunner(t),
|
runner: oscommands.NewFakeRunner(t),
|
||||||
expectedError: "an error occurred when removing file",
|
expectedError: "an error occurred when removing file",
|
||||||
@@ -115,7 +117,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
},
|
},
|
||||||
removeFile: func(string) error { return nil },
|
removeFile: func(string) error { return nil },
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "test"}, "", errors.New("error")),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "test"}, "", errors.New("error")),
|
||||||
expectedError: "error",
|
expectedError: "error",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -127,7 +129,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
},
|
},
|
||||||
removeFile: func(string) error { return nil },
|
removeFile: func(string) error { return nil },
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "test"}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "test"}, "", nil),
|
||||||
expectedError: "",
|
expectedError: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -140,7 +142,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
removeFile: func(string) error { return nil },
|
removeFile: func(string) error { return nil },
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"reset", "--", "test"}, "", nil).
|
ExpectGitArgs([]string{"reset", "--", "test"}, "", nil).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "test"}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "test"}, "", nil),
|
||||||
expectedError: "",
|
expectedError: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -153,7 +155,7 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
removeFile: func(string) error { return nil },
|
removeFile: func(string) error { return nil },
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"reset", "--", "test"}, "", nil).
|
ExpectGitArgs([]string{"reset", "--", "test"}, "", nil).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "test"}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "test"}, "", nil),
|
||||||
expectedError: "",
|
expectedError: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -190,7 +192,6 @@ func TestWorkingTreeDiscardAllFileChanges(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner, removeFile: s.removeFile})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner, removeFile: s.removeFile})
|
||||||
err := instance.DiscardAllFileChanges(s.file)
|
err := instance.DiscardAllFileChanges(s.file)
|
||||||
@@ -207,13 +208,14 @@ func TestWorkingTreeDiscardAllFileChanges(t *testing.T) {
|
|||||||
|
|
||||||
func TestWorkingTreeDiff(t *testing.T) {
|
func TestWorkingTreeDiff(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
file *models.File
|
file *models.File
|
||||||
plain bool
|
plain bool
|
||||||
cached bool
|
cached bool
|
||||||
ignoreWhitespace bool
|
ignoreWhitespace bool
|
||||||
contextSize int
|
contextSize uint64
|
||||||
runner *oscommands.FakeCmdObjRunner
|
similarityThreshold int
|
||||||
|
runner *oscommands.FakeCmdObjRunner
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectedResult = "pretend this is an actual git diff"
|
const expectedResult = "pretend this is an actual git diff"
|
||||||
@@ -226,12 +228,13 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: true,
|
Tracked: true,
|
||||||
},
|
},
|
||||||
plain: false,
|
plain: false,
|
||||||
cached: false,
|
cached: false,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--find-renames=50%", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "cached",
|
testName: "cached",
|
||||||
@@ -240,12 +243,13 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: true,
|
Tracked: true,
|
||||||
},
|
},
|
||||||
plain: false,
|
plain: false,
|
||||||
cached: true,
|
cached: true,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--cached", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--find-renames=50%", "--cached", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "plain",
|
testName: "plain",
|
||||||
@@ -254,12 +258,13 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: true,
|
Tracked: true,
|
||||||
},
|
},
|
||||||
plain: true,
|
plain: true,
|
||||||
cached: false,
|
cached: false,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=never", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=never", "--find-renames=50%", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "File not tracked and file has no staged changes",
|
testName: "File not tracked and file has no staged changes",
|
||||||
@@ -268,12 +273,13 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: false,
|
Tracked: false,
|
||||||
},
|
},
|
||||||
plain: false,
|
plain: false,
|
||||||
cached: false,
|
cached: false,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--find-renames=50%", "--no-index", "--", "/dev/null", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case (ignore whitespace)",
|
testName: "Default case (ignore whitespace)",
|
||||||
@@ -282,12 +288,13 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: true,
|
Tracked: true,
|
||||||
},
|
},
|
||||||
plain: false,
|
plain: false,
|
||||||
cached: false,
|
cached: false,
|
||||||
ignoreWhitespace: true,
|
ignoreWhitespace: true,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--ignore-all-space", "--find-renames=50%", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
@@ -296,22 +303,38 @@ func TestWorkingTreeDiff(t *testing.T) {
|
|||||||
HasStagedChanges: false,
|
HasStagedChanges: false,
|
||||||
Tracked: true,
|
Tracked: true,
|
||||||
},
|
},
|
||||||
plain: false,
|
plain: false,
|
||||||
cached: false,
|
cached: false,
|
||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 17,
|
contextSize: 17,
|
||||||
|
similarityThreshold: 50,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=17", "--color=always", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=17", "--color=always", "--find-renames=50%", "--", "test.txt"}, expectedResult, nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "Show diff with custom similarity threshold",
|
||||||
|
file: &models.File{
|
||||||
|
Name: "test.txt",
|
||||||
|
HasStagedChanges: false,
|
||||||
|
Tracked: true,
|
||||||
|
},
|
||||||
|
plain: false,
|
||||||
|
cached: false,
|
||||||
|
ignoreWhitespace: false,
|
||||||
|
contextSize: 3,
|
||||||
|
similarityThreshold: 33,
|
||||||
|
runner: oscommands.NewFakeRunner(t).
|
||||||
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--color=always", "--find-renames=33%", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
appState := &config.AppState{}
|
appState := &config.AppState{}
|
||||||
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
|
||||||
appState.DiffContextSize = s.contextSize
|
appState.DiffContextSize = s.contextSize
|
||||||
|
appState.RenameSimilarityThreshold = s.similarityThreshold
|
||||||
repoPaths := RepoPaths{
|
repoPaths := RepoPaths{
|
||||||
worktreePath: "/path/to/worktree",
|
worktreePath: "/path/to/worktree",
|
||||||
}
|
}
|
||||||
@@ -332,7 +355,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
reverse bool
|
reverse bool
|
||||||
plain bool
|
plain bool
|
||||||
ignoreWhitespace bool
|
ignoreWhitespace bool
|
||||||
contextSize int
|
contextSize uint64
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +371,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Show diff with custom context size",
|
testName: "Show diff with custom context size",
|
||||||
@@ -359,7 +382,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: false,
|
ignoreWhitespace: false,
|
||||||
contextSize: 123,
|
contextSize: 123,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--submodule", "--unified=123", "--no-renames", "--color=always", "1234567890", "0987654321", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "Default case (ignore whitespace)",
|
testName: "Default case (ignore whitespace)",
|
||||||
@@ -370,12 +393,11 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
ignoreWhitespace: true,
|
ignoreWhitespace: true,
|
||||||
contextSize: 3,
|
contextSize: 3,
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"-C", "/path/to/worktree", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
ExpectGitArgs([]string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "diff", "--no-ext-diff", "--submodule", "--unified=3", "--no-renames", "--color=always", "1234567890", "0987654321", "--ignore-all-space", "--", "test.txt"}, expectedResult, nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
appState := &config.AppState{}
|
appState := &config.AppState{}
|
||||||
@@ -397,30 +419,30 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
|||||||
|
|
||||||
func TestWorkingTreeCheckoutFile(t *testing.T) {
|
func TestWorkingTreeCheckoutFile(t *testing.T) {
|
||||||
type scenario struct {
|
type scenario struct {
|
||||||
testName string
|
testName string
|
||||||
commitSha string
|
commitHash string
|
||||||
fileName string
|
fileName string
|
||||||
runner *oscommands.FakeCmdObjRunner
|
runner *oscommands.FakeCmdObjRunner
|
||||||
test func(error)
|
test func(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
scenarios := []scenario{
|
scenarios := []scenario{
|
||||||
{
|
{
|
||||||
testName: "typical case",
|
testName: "typical case",
|
||||||
commitSha: "11af912",
|
commitHash: "11af912",
|
||||||
fileName: "test999.txt",
|
fileName: "test999.txt",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "11af912", "--", "test999.txt"}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "11af912", "--", "test999.txt"}, "", nil),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testName: "returns error if there is one",
|
testName: "returns error if there is one",
|
||||||
commitSha: "11af912",
|
commitHash: "11af912",
|
||||||
fileName: "test999.txt",
|
fileName: "test999.txt",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "11af912", "--", "test999.txt"}, "", errors.New("error")),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "11af912", "--", "test999.txt"}, "", errors.New("error")),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
},
|
},
|
||||||
@@ -428,11 +450,10 @@ func TestWorkingTreeCheckoutFile(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
|
|
||||||
s.test(instance.CheckoutFile(s.commitSha, s.fileName))
|
s.test(instance.CheckoutFile(s.commitHash, s.fileName))
|
||||||
s.runner.CheckForMissingCalls()
|
s.runner.CheckForMissingCalls()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -451,7 +472,7 @@ func TestWorkingTreeDiscardUnstagedFileChanges(t *testing.T) {
|
|||||||
testName: "valid case",
|
testName: "valid case",
|
||||||
file: &models.File{Name: "test.txt"},
|
file: &models.File{Name: "test.txt"},
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "test.txt"}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "test.txt"}, "", nil),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
@@ -459,7 +480,6 @@ func TestWorkingTreeDiscardUnstagedFileChanges(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.DiscardUnstagedFileChanges(s.file))
|
s.test(instance.DiscardUnstagedFileChanges(s.file))
|
||||||
@@ -479,7 +499,7 @@ func TestWorkingTreeDiscardAnyUnstagedFileChanges(t *testing.T) {
|
|||||||
{
|
{
|
||||||
testName: "valid case",
|
testName: "valid case",
|
||||||
runner: oscommands.NewFakeRunner(t).
|
runner: oscommands.NewFakeRunner(t).
|
||||||
ExpectGitArgs([]string{"checkout", "--", "."}, "", nil),
|
ExpectGitArgs([]string{"-c", disableHooksFlag, "checkout", "--", "."}, "", nil),
|
||||||
test: func(err error) {
|
test: func(err error) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
},
|
},
|
||||||
@@ -487,7 +507,6 @@ func TestWorkingTreeDiscardAnyUnstagedFileChanges(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.DiscardAnyUnstagedFileChanges())
|
s.test(instance.DiscardAnyUnstagedFileChanges())
|
||||||
@@ -515,7 +534,6 @@ func TestWorkingTreeRemoveUntrackedFiles(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.RemoveUntrackedFiles())
|
s.test(instance.RemoveUntrackedFiles())
|
||||||
@@ -545,7 +563,6 @@ func TestWorkingTreeResetHard(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 := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
|
||||||
s.test(instance.ResetHard(s.ref))
|
s.test(instance.ResetHard(s.ref))
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(worktrees))
|
wg.Add(len(worktrees))
|
||||||
for _, worktree := range worktrees {
|
for _, worktree := range worktrees {
|
||||||
worktree := worktree
|
|
||||||
|
|
||||||
go utils.Safe(func() {
|
go utils.Safe(func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
|
|||||||
@@ -181,7 +181,6 @@ branch refs/heads/mybranch-worktree
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (self *CachedGitConfig) Get(key string) string {
|
|||||||
defer self.mutex.Unlock()
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
if value, ok := self.cache[key]; ok {
|
if value, ok := self.cache[key]; ok {
|
||||||
self.log.Debugf("using cache for key " + key)
|
self.log.Debug("using cache for key " + key)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func (self *CachedGitConfig) GetGeneral(args string) string {
|
|||||||
defer self.mutex.Unlock()
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
if value, ok := self.cache[args]; ok {
|
if value, ok := self.cache[args]; ok {
|
||||||
self.log.Debugf("using cache for args " + args)
|
self.log.Debug("using cache for args " + args)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ func (self *CachedGitConfig) getGeneralAux(args string) string {
|
|||||||
cmd := getGitConfigGeneralCmd(args)
|
cmd := getGitConfigGeneralCmd(args)
|
||||||
value, err := self.runGitConfigCmd(cmd)
|
value, err := self.runGitConfigCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.log.Debugf("Error getting git config value for args: " + args + ". Error: " + err.Error())
|
self.log.Debugf("Error getting git config value for args: %s. Error: %v", args, err.Error())
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(value)
|
return strings.TrimSpace(value)
|
||||||
@@ -79,7 +79,7 @@ func (self *CachedGitConfig) getAux(key string) string {
|
|||||||
cmd := getGitConfigCmd(key)
|
cmd := getGitConfigCmd(key)
|
||||||
value, err := self.runGitConfigCmd(cmd)
|
value, err := self.runGitConfigCmd(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.log.Debugf("Error getting git config value for key: " + key + ". Error: " + err.Error())
|
self.log.Debugf("Error getting git config value for key: %s. Error: %v", key, err.Error())
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(value)
|
return strings.TrimSpace(value)
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ func TestGetBool(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) {
|
||||||
fake := NewFakeGitConfig(s.mockResponses)
|
fake := NewFakeGitConfig(s.mockResponses)
|
||||||
real := NewCachedGitConfig(
|
real := NewCachedGitConfig(
|
||||||
@@ -87,7 +86,6 @@ func TestGet(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) {
|
||||||
fake := NewFakeGitConfig(s.mockResponses)
|
fake := NewFakeGitConfig(s.mockResponses)
|
||||||
real := NewCachedGitConfig(
|
real := NewCachedGitConfig(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var githubServiceDef = ServiceDefinition{
|
|||||||
provider: "github",
|
provider: "github",
|
||||||
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}?expand=1",
|
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}?expand=1",
|
||||||
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}?expand=1",
|
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}?expand=1",
|
||||||
commitURL: "/commit/{{.CommitSha}}",
|
commitURL: "/commit/{{.CommitHash}}",
|
||||||
regexStrings: defaultUrlRegexStrings,
|
regexStrings: defaultUrlRegexStrings,
|
||||||
repoURLTemplate: defaultRepoURLTemplate,
|
repoURLTemplate: defaultRepoURLTemplate,
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ var bitbucketServiceDef = ServiceDefinition{
|
|||||||
provider: "bitbucket",
|
provider: "bitbucket",
|
||||||
pullRequestURLIntoDefaultBranch: "/pull-requests/new?source={{.From}}&t=1",
|
pullRequestURLIntoDefaultBranch: "/pull-requests/new?source={{.From}}&t=1",
|
||||||
pullRequestURLIntoTargetBranch: "/pull-requests/new?source={{.From}}&dest={{.To}}&t=1",
|
pullRequestURLIntoTargetBranch: "/pull-requests/new?source={{.From}}&dest={{.To}}&t=1",
|
||||||
commitURL: "/commits/{{.CommitSha}}",
|
commitURL: "/commits/{{.CommitHash}}",
|
||||||
regexStrings: []string{
|
regexStrings: []string{
|
||||||
`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
`^.*@.*:(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
`^.*@.*:(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
@@ -35,7 +35,7 @@ var gitLabServiceDef = ServiceDefinition{
|
|||||||
provider: "gitlab",
|
provider: "gitlab",
|
||||||
pullRequestURLIntoDefaultBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}",
|
pullRequestURLIntoDefaultBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}",
|
||||||
pullRequestURLIntoTargetBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}&merge_request[target_branch]={{.To}}",
|
pullRequestURLIntoTargetBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}&merge_request[target_branch]={{.To}}",
|
||||||
commitURL: "/-/commit/{{.CommitSha}}",
|
commitURL: "/-/commit/{{.CommitHash}}",
|
||||||
regexStrings: defaultUrlRegexStrings,
|
regexStrings: defaultUrlRegexStrings,
|
||||||
repoURLTemplate: defaultRepoURLTemplate,
|
repoURLTemplate: defaultRepoURLTemplate,
|
||||||
}
|
}
|
||||||
@@ -44,10 +44,11 @@ var azdoServiceDef = ServiceDefinition{
|
|||||||
provider: "azuredevops",
|
provider: "azuredevops",
|
||||||
pullRequestURLIntoDefaultBranch: "/pullrequestcreate?sourceRef={{.From}}",
|
pullRequestURLIntoDefaultBranch: "/pullrequestcreate?sourceRef={{.From}}",
|
||||||
pullRequestURLIntoTargetBranch: "/pullrequestcreate?sourceRef={{.From}}&targetRef={{.To}}",
|
pullRequestURLIntoTargetBranch: "/pullrequestcreate?sourceRef={{.From}}&targetRef={{.To}}",
|
||||||
commitURL: "/commit/{{.CommitSha}}",
|
commitURL: "/commit/{{.CommitHash}}",
|
||||||
regexStrings: []string{
|
regexStrings: []string{
|
||||||
`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
|
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
|
`^https://.*/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
},
|
},
|
||||||
repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}",
|
repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}",
|
||||||
}
|
}
|
||||||
@@ -56,7 +57,7 @@ var bitbucketServerServiceDef = ServiceDefinition{
|
|||||||
provider: "bitbucketServer",
|
provider: "bitbucketServer",
|
||||||
pullRequestURLIntoDefaultBranch: "/pull-requests?create&sourceBranch={{.From}}",
|
pullRequestURLIntoDefaultBranch: "/pull-requests?create&sourceBranch={{.From}}",
|
||||||
pullRequestURLIntoTargetBranch: "/pull-requests?create&targetBranch={{.To}}&sourceBranch={{.From}}",
|
pullRequestURLIntoTargetBranch: "/pull-requests?create&targetBranch={{.To}}&sourceBranch={{.From}}",
|
||||||
commitURL: "/commits/{{.CommitSha}}",
|
commitURL: "/commits/{{.CommitHash}}",
|
||||||
regexStrings: []string{
|
regexStrings: []string{
|
||||||
`^ssh://git@.*/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
`^ssh://git@.*/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||||
@@ -68,7 +69,7 @@ var giteaServiceDef = ServiceDefinition{
|
|||||||
provider: "gitea",
|
provider: "gitea",
|
||||||
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
|
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
|
||||||
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}",
|
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}",
|
||||||
commitURL: "/commit/{{.CommitSha}}",
|
commitURL: "/commit/{{.CommitHash}}",
|
||||||
regexStrings: defaultUrlRegexStrings,
|
regexStrings: defaultUrlRegexStrings,
|
||||||
repoURLTemplate: defaultRepoURLTemplate,
|
repoURLTemplate: defaultRepoURLTemplate,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,13 +51,13 @@ func (self *HostingServiceMgr) GetPullRequestURL(from string, to string) (string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HostingServiceMgr) GetCommitURL(commitSha string) (string, error) {
|
func (self *HostingServiceMgr) GetCommitURL(commitHash string) (string, error) {
|
||||||
gitService, err := self.getService()
|
gitService, err := self.getService()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
pullRequestURL := gitService.getCommitURL(commitSha)
|
pullRequestURL := gitService.getCommitURL(commitHash)
|
||||||
|
|
||||||
return pullRequestURL, nil
|
return pullRequestURL, nil
|
||||||
}
|
}
|
||||||
@@ -174,8 +174,8 @@ func (self *Service) getPullRequestURLIntoTargetBranch(from string, to string) s
|
|||||||
return self.resolveUrl(self.pullRequestURLIntoTargetBranch, map[string]string{"From": from, "To": to})
|
return self.resolveUrl(self.pullRequestURLIntoTargetBranch, map[string]string{"From": from, "To": to})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Service) getCommitURL(commitSha string) string {
|
func (self *Service) getCommitURL(commitHash string) string {
|
||||||
return self.resolveUrl(self.commitURL, map[string]string{"CommitSha": commitSha})
|
return self.resolveUrl(self.commitURL, map[string]string{"CommitHash": commitHash})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Service) resolveUrl(templateString string, args map[string]string) string {
|
func (self *Service) resolveUrl(templateString string, args map[string]string) string {
|
||||||
|
|||||||
@@ -210,6 +210,19 @@ func TestGetPullRequestURL(t *testing.T) {
|
|||||||
assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew&targetRef=dev", url)
|
assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew&targetRef=dev", url)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
testName: "Opens a link to new pull request on Azure DevOps Server (HTTP)",
|
||||||
|
from: "feature/new",
|
||||||
|
remoteUrl: "https://mycompany.azuredevops.com/collection/myproject/_git/myrepo",
|
||||||
|
configServiceDomains: map[string]string{
|
||||||
|
// valid configuration for a azure devops server URL
|
||||||
|
"mycompany.azuredevops.com": "azuredevops:mycompany.azuredevops.com",
|
||||||
|
},
|
||||||
|
test: func(url string, err error) {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "https://mycompany.azuredevops.com/collection/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew", url)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
testName: "Opens a link to new pull request on Bitbucket Server (SSH)",
|
testName: "Opens a link to new pull request on Bitbucket Server (SSH)",
|
||||||
from: "feature/new",
|
from: "feature/new",
|
||||||
@@ -413,11 +426,10 @@ func TestGetPullRequestURL(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) {
|
||||||
tr := i18n.EnglishTranslationSet()
|
tr := i18n.EnglishTranslationSet()
|
||||||
log := &fakes.FakeFieldLogger{}
|
log := &fakes.FakeFieldLogger{}
|
||||||
hostingServiceMgr := NewHostingServiceMgr(log, &tr, s.remoteUrl, s.configServiceDomains)
|
hostingServiceMgr := NewHostingServiceMgr(log, tr, s.remoteUrl, s.configServiceDomains)
|
||||||
s.test(hostingServiceMgr.GetPullRequestURL(s.from, s.to))
|
s.test(hostingServiceMgr.GetPullRequestURL(s.from, s.to))
|
||||||
log.AssertErrors(t, s.expectedLoggedErrors)
|
log.AssertErrors(t, s.expectedLoggedErrors)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
// Branch : A git branch
|
// Branch : A git branch
|
||||||
// duplicating this for now
|
// duplicating this for now
|
||||||
@@ -10,10 +13,14 @@ type Branch struct {
|
|||||||
DisplayName string
|
DisplayName string
|
||||||
// indicator of when the branch was last checked out e.g. '2d', '3m'
|
// indicator of when the branch was last checked out e.g. '2d', '3m'
|
||||||
Recency string
|
Recency string
|
||||||
// how many commits ahead we are from the remote branch (how many commits we can push)
|
// how many commits ahead we are from the remote branch (how many commits we can push, assuming we push to our tracked remote branch)
|
||||||
Pushables string
|
AheadForPull string
|
||||||
// how many commits behind we are from the remote branch (how many commits we can pull)
|
// how many commits behind we are from the remote branch (how many commits we can pull)
|
||||||
Pullables string
|
BehindForPull string
|
||||||
|
// how many commits ahead we are from the branch we're pushing to (which might not be the same as our upstream branch in a triangular workflow)
|
||||||
|
AheadForPush string
|
||||||
|
// how many commits behind we are from the branch we're pushing to (which might not be the same as our upstream branch in a triangular workflow)
|
||||||
|
BehindForPush string
|
||||||
// whether the remote branch is 'gone' i.e. we're tracking a remote branch that has been deleted
|
// whether the remote branch is 'gone' i.e. we're tracking a remote branch that has been deleted
|
||||||
UpstreamGone bool
|
UpstreamGone bool
|
||||||
// whether this is the current branch. Exactly one branch should have this be true
|
// whether this is the current branch. Exactly one branch should have this be true
|
||||||
@@ -28,6 +35,11 @@ type Branch struct {
|
|||||||
Subject string
|
Subject string
|
||||||
// commit hash
|
// commit hash
|
||||||
CommitHash string
|
CommitHash string
|
||||||
|
|
||||||
|
// How far we have fallen behind our base branch. 0 means either not
|
||||||
|
// determined yet, or up to date with base branch. (We don't need to
|
||||||
|
// distinguish the two, as we don't draw anything in both cases.)
|
||||||
|
BehindBaseBranch atomic.Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) FullRefName() string {
|
func (b *Branch) FullRefName() string {
|
||||||
@@ -41,6 +53,10 @@ func (b *Branch) RefName() string {
|
|||||||
return b.Name
|
return b.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Branch) ShortRefName() string {
|
||||||
|
return b.RefName()
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Branch) ParentRefName() string {
|
func (b *Branch) ParentRefName() string {
|
||||||
return b.RefName() + "^"
|
return b.RefName() + "^"
|
||||||
}
|
}
|
||||||
@@ -80,26 +96,30 @@ func (b *Branch) IsTrackingRemote() bool {
|
|||||||
// we know that the remote branch is not stored locally based on our pushable/pullable
|
// we know that the remote branch is not stored locally based on our pushable/pullable
|
||||||
// count being question marks.
|
// count being question marks.
|
||||||
func (b *Branch) RemoteBranchStoredLocally() bool {
|
func (b *Branch) RemoteBranchStoredLocally() bool {
|
||||||
return b.IsTrackingRemote() && b.Pushables != "?" && b.Pullables != "?"
|
return b.IsTrackingRemote() && b.AheadForPull != "?" && b.BehindForPull != "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) RemoteBranchNotStoredLocally() bool {
|
func (b *Branch) RemoteBranchNotStoredLocally() bool {
|
||||||
return b.IsTrackingRemote() && b.Pushables == "?" && b.Pullables == "?"
|
return b.IsTrackingRemote() && b.AheadForPull == "?" && b.BehindForPull == "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) MatchesUpstream() bool {
|
func (b *Branch) MatchesUpstream() bool {
|
||||||
return b.RemoteBranchStoredLocally() && b.Pushables == "0" && b.Pullables == "0"
|
return b.RemoteBranchStoredLocally() && b.AheadForPull == "0" && b.BehindForPull == "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) HasCommitsToPush() bool {
|
func (b *Branch) IsAheadForPull() bool {
|
||||||
return b.RemoteBranchStoredLocally() && b.Pushables != "0"
|
return b.RemoteBranchStoredLocally() && b.AheadForPull != "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) HasCommitsToPull() bool {
|
func (b *Branch) IsBehindForPull() bool {
|
||||||
return b.RemoteBranchStoredLocally() && b.Pullables != "0"
|
return b.RemoteBranchStoredLocally() && b.BehindForPull != "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Branch) IsBehindForPush() bool {
|
||||||
|
return b.RemoteBranchStoredLocally() && b.BehindForPush != "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// for when we're in a detached head state
|
// for when we're in a detached head state
|
||||||
func (b *Branch) IsRealBranch() bool {
|
func (b *Branch) IsRealBranch() bool {
|
||||||
return b.Pushables != "" && b.Pullables != ""
|
return b.AheadForPull != "" && b.BehindForPull != ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package models
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/fsmiamoto/git-todo-parser/todo"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/stefanhaller/git-todo-parser/todo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Special commit hash for empty tree object
|
// Special commit hash for empty tree object
|
||||||
@@ -43,7 +43,7 @@ const (
|
|||||||
|
|
||||||
// Commit : A git commit
|
// Commit : A git commit
|
||||||
type Commit struct {
|
type Commit struct {
|
||||||
Sha string
|
Hash string
|
||||||
Name string
|
Name string
|
||||||
Status CommitStatus
|
Status CommitStatus
|
||||||
Action todo.TodoCommand
|
Action todo.TodoCommand
|
||||||
@@ -54,20 +54,24 @@ type Commit struct {
|
|||||||
UnixTimestamp int64
|
UnixTimestamp int64
|
||||||
Divergence Divergence // set to DivergenceNone unless we are showing the divergence view
|
Divergence Divergence // set to DivergenceNone unless we are showing the divergence view
|
||||||
|
|
||||||
// SHAs of parent commits (will be multiple if it's a merge commit)
|
// Hashes of parent commits (will be multiple if it's a merge commit)
|
||||||
Parents []string
|
Parents []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) ShortSha() string {
|
func (c *Commit) ShortHash() string {
|
||||||
return utils.ShortSha(c.Sha)
|
return utils.ShortHash(c.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) FullRefName() string {
|
func (c *Commit) FullRefName() string {
|
||||||
return c.Sha
|
return c.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) RefName() string {
|
func (c *Commit) RefName() string {
|
||||||
return c.Sha
|
return c.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commit) ShortRefName() string {
|
||||||
|
return c.Hash[:7]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) ParentRefName() string {
|
func (c *Commit) ParentRefName() string {
|
||||||
@@ -86,7 +90,7 @@ func (c *Commit) ID() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) Description() string {
|
func (c *Commit) Description() string {
|
||||||
return fmt.Sprintf("%s %s", c.Sha[:7], c.Name)
|
return fmt.Sprintf("%s %s", c.Hash[:7], c.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commit) IsMerge() bool {
|
func (c *Commit) IsMerge() bool {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type File struct {
|
|||||||
HasInlineMergeConflicts bool
|
HasInlineMergeConflicts bool
|
||||||
DisplayString string
|
DisplayString string
|
||||||
ShortStatus string // e.g. 'AD', ' A', 'M ', '??'
|
ShortStatus string // e.g. 'AD', ' A', 'M ', '??'
|
||||||
|
LinesDeleted int
|
||||||
|
LinesAdded int
|
||||||
|
|
||||||
// If true, this must be a worktree folder
|
// If true, this must be a worktree folder
|
||||||
IsWorktree bool
|
IsWorktree bool
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ func (r *RemoteBranch) RefName() string {
|
|||||||
return r.FullName()
|
return r.FullName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RemoteBranch) ShortRefName() string {
|
||||||
|
return r.RefName()
|
||||||
|
}
|
||||||
|
|
||||||
func (r *RemoteBranch) ParentRefName() string {
|
func (r *RemoteBranch) ParentRefName() string {
|
||||||
return r.RefName() + "^"
|
return r.RefName() + "^"
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user