Compare commits

...

1693 Commits

Author SHA1 Message Date
Jesse Duffield
6636d0c15a Fix auto-release workflow (#4265)
The latest_tag env var wasn't defined when it was used.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-15 15:37:50 +11:00
Jesse Duffield
269d89ea51 Fix issue where latest tag wasn't obtained early enough in auto-release script 2025-02-15 15:36:54 +11:00
Jesse Duffield
dcf264b182 README.md: Update Sponsors (#4177)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2025-02-15 15:24:27 +11:00
github-actions[bot]
e37d7d5ad2 README.md: Update Sponsors 2025-02-15 04:23:38 +00:00
Jesse Duffield
988162848a Don't try killing processes if we already know the command finished + reduce error logging noise on Windows (#4231)
- **PR Description**

I was tinkering around with the code and then checking associated logs
but even with LOG_LEVEL=error, I found there was a lot of noise on
Windows.

This PR fixes two such sources:
1. Navigating through files in the Files panel
1. Navigating through branches in the Branches panel when there are a
lot of commits (e.g. this repo)

More details in the comments below.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-15 15:23:26 +11:00
Brandon
ed9519a241 Suppress error logs when killing process on Windows
There is a string check here to suppress the failure logs due to this reason but on Windows, the string is different ("exit status 1").
2025-02-15 14:51:35 +11:00
Brandon
7731311674 Don't try killing processes if we already know the command finished
This may lead to unrelated processes being killed on Windows (https://github.com/jesseduffield/lazygit/issues/3008). Imagine:
1. lazygit is started and runs git diff in process X which completes immediately and exits.
2. lazygit is left in the background for several hours by which process X pid is reused by an unrelated process.
3. lazygit is focused back on and runs another git diff. It first runs this stop logic which will kill process X and its children.
2025-02-15 14:51:35 +11:00
Stefan Haller
853a04dfd0 Update translations; includes a new Portuguese translation (#4250)
- **PR Description**

Update translations from Crowdin.
2025-02-12 08:23:56 +01:00
Stefan Haller
c02709698c Update translations from Crowdin
This adds a new Portuguese translation.
2025-02-12 08:21:47 +01:00
Stefan Haller
555ab8735a Change update_language_files.sh script to rename pt-PT to pt 2025-02-12 08:21:47 +01:00
Stefan Haller
20fe43f972 Add some more information to pkg/i18n/translations/README.md 2025-02-12 08:21:47 +01:00
Stefan Haller
0fd7b9baa4 Fix json schema for context of CustomCommand (#4255)
- **PR Description**

Fix ugly error squiggles in VS Code when using a custom command with a
context of e.g. "commits, subCommits".

Previously the schema only allowed a single value for the context field;
however, it is now possible to specify multiple values separated by
comma (see #3784).

The only solution that I can see is to get rid of the "enum"
specification, and mention the valid values only in the description. Add
examples too so that you get at least auto-completion.
2025-02-12 08:21:06 +01:00
Stefan Haller
19921b7c42 Fix json schema for context of CustomCommand
Previously the schema only allowed a single value; however, it is now possible
to specify multiple values separated by comma, and you would get very ugly red
error squiggles in VS Code when you did that.

The only solution that I can see is to get rid of the "enum" specification, and
mention the valid values only in the description. Add examples too so that you
get at least auto-completion.
2025-02-12 08:18:26 +01:00
Stefan Haller
c37376af74 fix: properly detect icon for BAZEL and WORKSPACE files (#4252)
- **PR Description**
We were using lowercase for checking the `BUILD` and `WORKSPACE` file
names when they are always uppercase. Fix these.
2025-02-11 21:46:38 +01:00
Peter Cardenas
9dbde94952 fix: properly detect icon for BAZEL and WORKSPACE files 2025-02-11 11:26:18 -08:00
Stefan Haller
3915cb6e71 Fix pasting multi-line text into commit message panel (#4234)
- **PR Description**

When pasting a multi-line commit message into the subject field of the
commit editor, we would interpret the first newline as the confirmation
for closing the editor, and then all remaining characters as whatever
command they are bound to, resulting in executing all sorts of arbitrary
commands.

Now we recognize this being a paste, and interpret the first newline as
moving to the description.

Also, prevent tabs in the pasted content from switching to the
respective other panel; simply insert four spaces instead, which should
be good enough for the leading indentation in pasted code snippets, for
example.

Finally, disable pasting text into non-editable views; my assumption is
that this is always a mistake, as it would execute arbitrary commands
depending on what's in the clipboard.

This depends on the terminal emulator supporting bracketed paste; I
didn't find one on Mac that doesn't (I tested with Terminal.app, iTerm2,
Ghostty, kitty, Alacritty, WezTerm, and VSCode's builtin terminal. It
works well in all of them).

I couldn't get it to work in Windows Terminal though, and I don't
understand why, as it does seem to support bracketed paste (it works in
bash).

Fixes #3151
Fixes #4066
Fixes #4216
2025-02-10 13:44:05 +01:00
Stefan Haller
ba6cfc1f85 Handle pasting multi-line commit messages
When pasting a multi-line commit message into the subject field of the commit
editor, we would interpret the first newline as the confirmation for closing the
editor, and then all remaining characters as whatever command they are bound to,
resulting in executing all sorts of arbitrary commands.

Now we recognize this being a paste, and interpret the first newline as moving
to the description.

Also, prevent tabs in the pasted content from switching to the respective other
panel; simply insert four spaces instead, which should be good enough for the
leading indentation in pasted code snippets, for example.
2025-02-10 13:40:25 +01:00
Stefan Haller
46ebfbbe87 Bump gocui 2025-02-10 13:40:22 +01:00
Stefan Haller
3012306ac3 Swap position of checkout-commit and checkout-branch menu items (#4238)
- **PR Description**

Fixes #4237.
2025-02-10 13:37:34 +01:00
Stefan Haller
e987d4b519 Swap position of checkout-commit and checkout-branch menu items
Jesse's comment from https://github.com/jesseduffield/lazygit/issues/4237:

We recently added a new option to check out a commit's branch from within the
commits, reflog, and sub-commits panels:

https://github.com/user-attachments/assets/0a5cf3f2-6803-4709-ae5a-e4addc061012

After using it for some time, I find it annoying that the default option has
changed. I rarely find myself wanting to check out a branch from the commits
panel, and it's rarer still to want to check out a branch from the reflog and
sub-commits panel. Although there may be use cases for this, it is jarring that
something you can always do (checkout the commit) is harder to do than something
that you can sometimes do (checkout the branch).

We've also had a user complain (see
https://github.com/jesseduffield/lazygit/pull/4117) about their muscle-memory
being broken by the recent change, and I have also fallen victim to this. I
don't think that the new branch checkout option is sufficiently useful to
dislodge the existing keybinding, so let's swap them.
2025-02-10 13:35:01 +01:00
Stefan Haller
190954568e Bump go-deadlock version to fix crash with go 1.23 in debug mode (#4248)
- **PR Description**

This PR solves https://github.com/jesseduffield/lazygit/issues/4002, and
perhaps https://github.com/jesseduffield/lazygit/issues/3880 (if they
are indeed duplicates), and the error message preventing debugging in
https://github.com/jesseduffield/lazygit/issues/3973.

The problem is that our version of `go-deadlock` transitively depends on
a version of `goid` that predates their changes to support go `1.23`,
which results in every goid being the number `2` for some reason.
Bumping the version of `go-deadlock` to include the updated transitive
dependency means that the goids are now correct, and `go-deadlock` does
not confused why goroutine 2 is trying to lock so many things.

I know very little about go vendored dependencies, so all I have done is
edit the `go.mod` entry for `go-deadlock` to be v0.3.5, and then run a
`go mod tidy` and `go mod vendor`. If there is a more correct way to
bump a vendored dependency, feel free to close this PR and just do that!
2025-02-10 13:23:54 +01:00
Chris McDonnell
f117eed614 go-deadlock version bump to fix crash with go 1.23 2025-02-10 01:43:35 -05:00
Stefan Haller
a5698b86fa Improve contrast of highlighted search results (#4242)
- **PR Description**

Bump gocui to include https://github.com/jesseduffield/gocui/pull/73.

Fixes #4162.
2025-02-07 14:27:45 +01:00
Stefan Haller
050a91b7d1 Bump gocui
This improves the contrast of highlighted search results by setting the
foreground color to black.
2025-02-07 14:20:49 +01:00
Stefan Haller
0b524293e1 Fix possible crash when deleting a branch while filtering is active (#4195)
- **PR Description**

Fix #4179.
2025-02-07 09:37:55 +01:00
Stefan Haller
ff4ae4a544 Fix possible crash when deleting a branch while filtering is active
The code that tries to reselect the same branch again uses GetItems, which in
case of filtering is the filtered list. After replacing the branches slice with
a new one, the filtered list is no longer up to date, so we must reapply the
filter before working with it. It so happens that refreshView does that, so
simply call that before setting the selection again; I don't think the order
matters in this case. Otherwise we'd have to insert another call to
ReApplyFilter before the call to GetItems, which we can avoid this way.

Note that this doesn't actually make anything work better in the case of
deleting a branch, since we can't reselect the deleted branch anyway of course.
But it avoids a possible crash if the branch that was deleted was the last one
in the unfiltered list.
2025-02-07 09:34:25 +01:00
Stefan Haller
a0aa7a1940 Preserve pending commit message when closing/re-opening (#4191)
- **PR Description**
This PR allows lazygit to preserve the commit messages when the commit
popup gets closed.

While discussing the feature as part of its issue, two approaches were
taken into consideration:
- to store the commit content as part of the global state file
- to store the commit content in a special file to place inside the
`.git` folder

I opted for the second approach to avoid worrying about associating each
preserved message to the worktree it belongs to. I am happy to
reconsider this and opt for the alternative approach, but I wanted to
discuss this with the maintainers before deciding.

Note: The preserving file (`.git/LAZYGIT_PENDING_COMMIT`) is deleted
when the commit is finalized or when the commit content becomes empty.
2025-02-07 09:31:56 +01:00
AzraelSec
6065908b0d Improve and adapt commit persistence test-cases 2025-02-07 09:28:27 +01:00
AzraelSec
a32be7e9fa Implement reboot-resistant commit message persistence 2025-02-07 09:28:27 +01:00
Stefan Haller
fcf30caf40 Show files filter status (#4230)
- **PR Description**

This PR contains three improvements to the Files panel filtering:
- it allows the user to switch to a different filter type (or reset the
filter) when we are auto-showing only conflicting files
- it shows the filter menu as radio buttons
- it displays the current filter in the top-right corner of the Files
panel's frame

See the individual commits for details.
2025-02-07 09:27:23 +01:00
Stefan Haller
aad2622278 Show filter state in top right corner of Files panel frame
This includes the "only conflicting" status that the user can't switch to
themselves. We display it anyway to give a hint that files are being filtered,
and to let them know that they can turn the filter off if they want to.
2025-02-07 09:24:24 +01:00
Stefan Haller
2f4cedd025 Show current files filter as radio buttons
I renamed the "Reset filter" item to "No filter" to make it look more like a
state than an action, so that it fits the radio button concept better.

When there are conflicts and we set the filter to show only conflicting files,
then none of the radio buttons light up, which is slightly strange. I guess it's
ok though.
2025-02-07 09:24:24 +01:00
Stefan Haller
e883f74f3c Allow user to switch filter when showing only conflicts
We don't need to maintain additional state to allow this; all we need to do is
take over the filter only when the number of conflicting files goes from zero to
non-zero, rather than every time it is non-zero.

The only problem is that we don't allow users to go back to showing only
conflicted files, but that's just because we don't have that as an entry in the
menu. And I don't think it's a problem.
2025-02-07 09:24:24 +01:00
Jesse Duffield
a1838d33e7 Allow user to filter the files view to only show untracked files (#4226)
This handles the situation where the user's own config says to not show
untracked files, as is often the case with bare repos managing a user's
dotfiles.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-02-07 09:08:23 +11:00
Jesse Duffield
7e85cdd027 Allow user to filter the files view to only show untracked files
This handles the situation where the user's own config says to not show
untracked files, as is often the case with bare repos managing a user's
dotfiles.
2025-02-07 09:04:55 +11:00
Stefan Haller
31e54eadaa Fix incorrect stash diff after rename (#4213)
- **PR Description**

Reproduction:
```bash
git init
git commit --allow-empty -m "first commit"
touch file1
git add .
git stash push -m "stash1"
touch file2
git add .
git stash push -m "stash2"
lazygit
```
Navigate to the Stash view and rename stash 1

![image](https://github.com/user-attachments/assets/f43b065c-9d28-4375-a5d7-cfe39a4bf216)

Manually refreshing fixes the diff.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-02-06 10:09:21 +01:00
Brandon
02ca07a9be Fix incorrect stash diff after rename 2025-02-06 09:55:26 +01:00
Stefan Haller
5dff9af027 Disable staging and unstaging lines or hunks when the diff context size is 0 (#4235)
- **PR Description**

Git diff and patch doesn't work reliably with a context size of 0, so
disable it in this case (and discarding changes as well). Magit does the
same, see https://github.com/magit/magit/issues/4222.

Staging entire files by pressing space in the Files panel is still
possible, of course.

Fixes #4233.
2025-02-06 08:53:43 +01:00
Stefan Haller
437daf2f74 Disable staging and unstaging lines or hunks when the diff context size is 0
Git diff and patch doesn't work reliably with a context size of 0, so disable it
in this case (and discarding changes as well). Magit does the same, see
https://github.com/magit/magit/issues/4222.

Staging entire files by pressing space in the Files panel is still possible, of
course.
2025-02-05 16:07:22 +01:00
Stefan Haller
c0141685fe Fix tag being truncated when copying to clipboard (#4232)
Copy the whole tag to clipboard instead of truncating to the value of
TruncateCopiedCommitHashesTo.

- **PR Description**
My PR for copying the tag to clipboard was recently merged (#4219).
While using LazyGit built from the latest master I noticed that some
tags were being truncated, turns out it was due to a bug I introduced on
that previous PR.
Sorry for that.
2025-02-04 08:57:22 +01:00
Bruno Jesus
4856c96521 Fix tag truncated when copying to clipboard
Copy the whole tag to clipboard instead of truncating to the value of
TruncateCopiedCommitHashesTo.
2025-02-03 21:25:34 +00:00
Stefan Haller
49f8dc2ce4 Improve error reporting on config migration (#4210)
- **PR Description**

closes #4209

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 09:14:18 +01:00
Karem Abdul-Samad
afc3061c51 Improve error reporting on config migration 2025-01-30 09:01:17 +01:00
Stefan Haller
2bed09ef67 Show confirmation menu when trying to amend changes while there are conflicts (#4222)
- **PR Description**

Show confirmation menu when trying to amend changes while there are
conflicts, as this is very likely not what users want at that point.
Resolves #4208.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:55:56 +01:00
Stefan Haller
0a78d0016e Show confirmation menu when trying to amend changes while there are conflicts 2025-01-30 08:53:34 +01:00
Stefan Haller
c0e3922d02 Fix flicker when showing backround fetch status (#4223)
- **PR Description**

Fix occasional ugly flicker when showing the background fetch status
(recently introduced with #4215).

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:52:37 +01:00
Stefan Haller
638c9c5fe7 Fix flicker when showing the status of a background fetch
This was recently introduced, but it was done the wrong way.
WithWaitingStatusSync should only be called from the main thread, and it is
meant to be used for updating the bottom line while the UI is blocked. It is a
bad idea to call this from a background thread, and it results in ugly flicker
(occasionally).

Use the newly extracted WithWaitingStatusImpl instead, this is the same as
WithWaitingStatus (which is exactly what we need) but without the implicit
OnWorker, which we don't want because we are on a background thread already.
2025-01-30 08:49:58 +01:00
Stefan Haller
e48e7a2ebc Extract the inner part of WithWaitingStatus as a synchronous variant of it
This is the same as WithWaitingStatus but without the implicit OnWorker, for
those who are on a background thread already.
2025-01-30 08:49:58 +01:00
Jesse Duffield
d2723ff2dd Add option to delete local and remote tag (#4217)
- **PR Description**

Option to delete both local and remote tag, closes #4203.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-30 09:36:12 +11:00
Anvar Umuraliev
7db8fb8e9c Add option to delete local and remote tag 2025-01-30 09:05:17 +11:00
Jesse Duffield
abf914c923 Copy tags to clipboard (#4218)
- **PR Description**

This PR adds a new feature that allows users to copy tags to the
clipboard.
It can be used from the Commits "Copy to clipboard" menu and also from
the Tags list.
Closes #4219 

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-30 08:56:07 +11:00
Bruno Jesus
698f9287d4 Rename NoTags to CommitHasNoTags 2025-01-28 23:11:06 +00:00
Bruno Jesus
632695f71c Integration tests for copy tags to clipboard
Adds integration test in order to confirm if tags are being properly
sent to the clipboard
2025-01-28 00:34:57 +00:00
Bruno Jesus
ef0d319686 Add copy commit tags to clipboard toast message 2025-01-28 00:33:55 +00:00
Bruno Jesus
0397ede8a6 Document copy tag keybinding
Add the default keybinding for the "Copy tag to clipboard" function on
the Tags section.
2025-01-27 22:07:08 +00:00
Bruno Jesus
333802fffc Copy Tags to clipboard
Add an option to copy tag(s) to the clipboard.

Works on both the Tags and Commits sections.
2025-01-27 21:53:13 +00:00
Stefan Haller
3722824298 Show background fetch status in bottom line (#4215)
- **PR Description**

This shows a status as if the user had typed 'f' manually in the files panel.

I want this particularly for the first fetch after startup. There are often
situations where I need to wait for this first background fetch to be done
before I can do what I want (e.g. rebase my branch onto its base branch, or
check out a branch that my coworker has told me they just pushed), but currently
it's hard to tell when that is.

For every subsequent background fetch after the first one it is less important,
but it hopefully doesn't hurt, and it might be nice to have some visual indication 
that background activity is happening.
2025-01-27 14:01:05 +01:00
Stefan Haller
542478546d Show background fetch status in bottom line
This shows a status as if the user had typed 'f' manually in the files panel.

I want this particularly for the first fetch after startup. There are often
situations where I need to wait for this first background fetch to be done
before I can do what I want (e.g. rebase my branch onto its base branch, or
check out a branch that my coworker has told me they just pushed), but currently
it's hard to tell when that is.

For every subsequent background fetch after the first one it is less important,
but it hopefully doesn't hurt, and it might be nice to have some visual
indication that background activity is happening.
2025-01-27 13:59:04 +01:00
Stefan Haller
9ea2ff8f41 Remove call to Render()
As far as I can tell, this is not needed. The call to Refresh at the end of
backgroundFetch takes care of redrawing after refreshing.

The call was added in 2fc1498517, that's a long time ago, and we had multiple
big refactorings since then. Maybe it was needed back then but no longer is
today.
2025-01-27 13:59:04 +01:00
Stefan Haller
55236802c3 Expose {{.SelectedCommitRange}} to custom commands (#4204)
- **PR Description**

Expose `{{.SelectedCommitRange}}` to custom commands. It has fields .To
and .From (the hashes of the last and the first selected commits,
respectively), and it is useful for creating git commands that act on a
range of commits.

Fixes #4184.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-27 09:03:47 +01:00
Stefan Haller
4baf008ac7 Expose {{.SelectedCommitRange}} to custom commands
It has fields .To and .From (the hashes of the last and the first selected
commits, respectively), and it is useful for creating git commands that act on a
range of commits.
2025-01-27 08:53:50 +01:00
Stefan Haller
d768327814 Fix checking out a different branch while pushing a branch for the first time (#4214)
- **PR Description**

When pushing a branch that didn't have an upstream yet, we use the
command line

  git push --set-upstream origin HEAD:branch-name

The HEAD: part of this is too unspecific; when checking out a different
branch while the push is still running, then git will set the upstream
branch on the newly checked out branch, not the branch that was being
pushed. This might be considered a bug in git; you might expect that it
resolves HEAD at the beginning of the operation, and uses the result at
the end.

But we can easily work around this by explicitly supplying the real
branch name instead of HEAD.

Fixes #4207.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-27 08:50:24 +01:00
Stefan Haller
0864affc8f Fix checking out a different branch while pushing a branch for the first time
When pushing a branch that didn't have an upstream yet, we use the command line

  git push --set-upstream origin HEAD:branch-name

The HEAD: part of this is too unspecific; when checking out a different branch
while the push is still running, then git will set the upstream branch on the
newly checked out branch, not the branch that was being pushed. This might be
considered a bug in git; you might expect that it resolves HEAD at the beginning
of the operation, and uses the result at the end.

But we can easily work around this by explicitly supplying the real branch name
instead of HEAD.
2025-01-26 10:22:19 +01:00
Stefan Haller
40d6800fd3 Fix adding blank line at end of commit message (#4182)
- **PR Description**

This fixes a bug where adding enough new lines to a commit message
description such that it becomes taller than the window so that the
window needs to resize vertically, the cursor wouldn't move to the added
blank line, but stay at the end of the previous line. This was a
regression introduced with #4152.
2025-01-20 17:54:59 +01:00
Stefan Haller
20d0b4316d Only avoid the blank line at end of view if view is not editable
For editable views it is important to actually show the blank line so that we
can put the cursor there for typing.

This fixes problems with adding blank lines at the end of longer commit
messages.
2025-01-20 17:52:53 +01:00
Stefan Haller
fe429c6184 Bump gocui 2025-01-20 17:52:51 +01:00
Stefan Haller
a77dcbe3a1 Add '--' to 'git rev-list' to disambiguate branch name from path (#4185)
- **PR Description**

When deleting a local branch that has the same name as a file known to
git (say `test`), a popup with the following error is shown:
```
fatal: ambiguous argument 'test': both revision and filename
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]' 
```
The command log reveals this:
```
git rev-list --max-count=1 test ^HEAD ^refs/heads/main
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-20 09:25:50 +01:00
Erich Fussi
2a87c048b9 Add '--' to 'git rev-list' to disambiguate branch name from path 2025-01-19 14:33:42 +01:00
Jesse Duffield
c03b892270 Bump tcell to fix broken deployment (#4178)
- **PR Description**

See
https://github.com/jesseduffield/lazygit/actions/runs/12829856652/job/35776769332
and https://github.com/gdamore/tcell/issues/768
2025-01-18 00:36:18 +11:00
Jesse Duffield
5e26183ae1 Bump tcell to fix broken deployment 2025-01-18 00:31:57 +11:00
Jesse Duffield
ab7b5f6d84 Improve undo action to restore files upon undoing a commit (#4167)
- **PR Description**

Right now, undoing a commit performs a hard reset, which also discards
all the changes from that commit. This PR adds new config options (and a
new `undo` section) which allow users to choose between `hard` and
`soft` reset modes when undoing commits.

Personally, I think that the default should be `soft`, because the state
before the commit had the files, so undoing a commit should put the
files where they were before. But this PR keeps `hard` as the default
and does not change current behavior.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-18 00:17:12 +11:00
Gabriel Lanata
4065175a58 Improve undo action to restore files upon undoing a commit 2025-01-18 00:07:15 +11:00
Stefan Haller
43106b6c7f Collapse/uncollapse all files in tree (#4131) 2025-01-13 21:18:38 +01:00
Mauricio Trajano
7bea41534b Collapse/expand all files in tree
Co-authored-by: Stefan Haller <stefan@haller-berlin.de>
2025-01-13 21:13:11 +01:00
Stefan Haller
14a91d9829 Bump gocui (and tcell) (#4166)
This updates our tcell dependency to v2.8.0, adding support for ghostty
and tmux-256color.

This will hopefully fix #4133, and it might also fix #2962 and #3434
(but I don't understand enough about these to tell).
2025-01-12 13:51:33 +01:00
Stefan Haller
274e24d75e Bump gocui (and tcell)
This updates our tcell dependency to v2.8.0, adding support for ghostty and
tmux-256color.
2025-01-12 13:48:52 +01:00
Stefan Haller
a1a8cd114d Add ability to configure branch color patterns using regex (#4130)
- **PR Description**

Add ability to specify color patterns in the `branchColorPatterns`
config using regex, ex. `JIRA-\d+` would match all branch names in the
form `JIRA-456`.

Example config:
```yaml
gui:
  branchColorPatterns:
    'docs/.+': 'black' # make all branches prefixed with docs/ have a black color
    'feature/collapse-all': 'red' # make a specfic branch name red
    'IDEA-\d+': 'blue' # make all branches with the prefix `IDEA-` followed by a digit, blue

```
2025-01-12 13:47:17 +01:00
Mauricio Trajano
c64a7904b7 Add ability to configure branch color patterns 2025-01-12 13:44:26 +01:00
Stefan Haller
3e623cd1ce Remove the automatic coloring of certain branch names
We used to automatically color branches starting with "feature/", "bugfix/", or
"hotfix/". For those who don't want this, it's a bit non-obvious to turn off,
but it's actually pretty easy to configure manually for those who want this, so
we just remove this default coloring.
2025-01-11 22:13:33 +01:00
Jesse Duffield
6da99a49a4 Cut a new release automatically each month (#4146)
- **PR Description**

I regularly struggle to stay on top of releases, and that's because I
like to spend some time polishing the release notes and I don't always
have time for that. But that shouldn't block releases, so now releases
will happen automatically on the first Saturday of each month.

In order to block an automatic release, we simply need to add a
blocks-release label on any open PR or issue.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-11 15:47:43 +11:00
Jesse Duffield
977a01172f Automatically cut release each month 2025-01-11 15:44:00 +11:00
Jesse Duffield
91cb1ff29a Standardise on 'screen mode' naming convention (#4142)
We had some conflicting names: screen-mode, window-size, and
window-maximisation. I think panel-size sounds good.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-11 14:30:12 +11:00
Jesse Duffield
28d10c26a4 Standardise on 'screen mode' name
We had some conflicting names so we're standardising on screen mode
2025-01-11 14:25:48 +11:00
Stefan Haller
2c321011db Use interactive shell for running shell commands only if shell is bash or zsh (#4159)
- **PR Description**

Fix running shell commands with fish or nushell.

Fixes #4153.
2025-01-10 00:26:35 +01:00
Stefan Haller
dbd407c01d Use interactive shell for running shell commands only if shell is bash or zsh
We use an interactive shell so that users can use their custom shell aliases in
lazygit's shell prompt, which is convenient; however, this only really works for
shells like bash or zsh. We know it doesn't work for fish or nushell (because
these use different names for the $? variable); so use an interactive shell only
if the user's shell is either bash or zsh.
2025-01-09 09:29:31 +01:00
Stefan Haller
b8d5e481bb Fix micro editor preset (#4156)
- **PR Description**

I don't know what was I thinking when making #3049, because Micro does
not actually support `--` as delimiter between options and files. As
such, when trying to edit files with `micro` set as editor, an empty
file named `--` would be open first.

This PR fixes this by explicitly defining a preset for `micro`. I've
double-tested it to make sure that it doesn't behave wierdly any more :D
2025-01-09 08:51:39 +01:00
Nikita Karamov
2b3525bfd6 Fix micro editor preset 2025-01-09 08:48:59 +01:00
Stefan Haller
b2c46c33b6 Add number of commits to cherry-pick confirmation prompt (#4158)
- **PR Description**

The other day, I was cherry-picking a selection of commits and was
annoyed that the "Are you sure..." prompt did not include the actual
number of commits I was about to cherry-pick.

I failed to realize the number of copied commits is displayed at the
bottom right until going to update the integration tests. I personally
think it's still nice to display the number in the actual confirmation
prompt but feel free to close this PR if the change is unwanted.
2025-01-09 08:46:37 +01:00
Brandon
c44231a7d7 Add number of commits to cherry-pick confirmation prompt 2025-01-08 21:08:42 -08:00
Jesse Duffield
3518ec9f72 README.md: Update Sponsors (#3746)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2025-01-09 11:26:19 +11:00
github-actions[bot]
ec19fcf134 README.md: Update Sponsors 2025-01-09 00:25:30 +00:00
Stefan Haller
2d193cb296 Adjust line number for working copy when editing a line (#4119)
- **PR Description**

There are two ways to jump to the editor on a specific line: pressing `e` in the
staging or patch building panels, or clicking on a hyperlink in a delta diff. In
both cases, this works perfectly in the unstaged changes view, but in other
views (either staged changes, or an older commit) it can often jump to the wrong
line; this happens when there are further changes to the file being viewed in
later commits or in unstaged changes.

This commit fixes this so that you end up on the right line in these cases.
2025-01-07 17:50:01 +01:00
Stefan Haller
64cd7cd9f6 Adjust line number for working copy when editing a line
There are two ways to jump to the editor on a specific line: pressing `e` in the
staging or patch building panels, or clicking on a hyperlink in a delta diff. In
both cases, this works perfectly in the unstaged changes view, but in other
views (either staged changes, or an older commit) it can often jump to the wrong
line; this happens when there are further changes to the file being viewed in
later commits or in unstaged changes.

This commit fixes this so that you end up on the right line in these cases.
2025-01-07 17:46:51 +01:00
Stefan Haller
eaaf123238 Combine GetPathDiff and GetAllDiff into one command (GetDiff)
This makes it more reusable for other purposes.
2025-01-07 17:46:51 +01:00
Stefan Haller
1c5fe8ff17 Add a test demonstrating the problem
When pressing `e` on line 5 in a diff of an older commit, we expect it to take
us to line 5 in that file. But we end up on line 2, because the file had further
changes both in newer commits, and in the unstaged changes of the working copy.
2025-01-07 17:46:51 +01:00
Stefan Haller
49ca7f6a84 Bump gocui 2025-01-07 17:39:01 +01:00
Stefan Haller
80c212faba Avoid blank line at end of view (#4152)
- **PR Description**

This updates gocui to include
https://github.com/jesseduffield/gocui/pull/68 and
https://github.com/jesseduffield/gocui/pull/69, which changes views to
not have an extra blank line at the end when content ending in a newline
character is written to them. This makes text views more consistent with
list views, which don't have a blank line after the last list entry
either.
2025-01-07 17:37:57 +01:00
Stefan Haller
ae53059ed2 Bump gocui
This updates gocui to include https://github.com/jesseduffield/gocui/pull/68 and
https://github.com/jesseduffield/gocui/pull/69, which changes views to not have
an extra blank line at the end when content ending in a newline character is
written to them. This makes text views more consistent with list views, which
don't have a blank line after the last list entry either.
2025-01-07 17:34:30 +01:00
Stefan Haller
13829d8ff7 Fix reset/rebase to upstream (#4151)
- **PR Description**

Resetting to the upstream branch was broken when the remote branch has a
different name than the local branch.

Rebasing onto the upstream worked fine, but also displayed the wrong
branch name in the menu.

Fixes #4148.
2025-01-06 09:31:44 +01:00
Stefan Haller
53b1e12110 Cleanup: use the upstream local variable consistently
We need to move it closer to the beginning of the method to use it everywhere.
2025-01-04 15:48:26 +01:00
Stefan Haller
009062534e Fix resetting or rebasing a branch to its upstream when the upstream branch name is different 2025-01-04 15:48:26 +01:00
Stefan Haller
33e81f717d Extend reset/rebase test to use upstream branch name that is different from local one
The easiest way to do that is to rename the local branch after pushing.

This shows various levels of brokenness for the reset and rebase to upstream
commands: both menu entries display the wrong upstream branch name in the menu
(the local one rather than the remote one); executing the rebase command works
correctly though, the rebase command uses the right branch name. Resetting
fails, though.

We'll fix this in the next commit.
2025-01-04 15:46:14 +01:00
Stefan Haller
ef718f3386 Show the alt-enter keybinding at bottom of commit description view (#4136)
- **PR Description**

It wasn't really obvious how to commit when the focus is in the commit
description view, since pressing enter inserts a newline there. To
improve this, show the `<a-enter>` keybinding at the bottom of the
description view when it is focused.

Fixes #4134.
2025-01-03 10:19:14 +01:00
Stefan Haller
bf9339557e Show the <a-enter> keybinding at bottom of commit description view
It was hard to discover, this should make it more obvious.
2025-01-03 10:16:29 +01:00
Stefan Haller
ebfc7ff7c6 Don't show keybindings option in bottom line when panel is open (#4143)
- **PR Description**

Hide the `Keybindings: ?` option from the bottom line if a panel is open.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2025-01-03 10:13:20 +01:00
Stefan Haller
928e76a82f Disable KeybindingsMenu using a DisabledReason when a panel is open
This hides it from the options map at the bottom of the screen.
2025-01-03 10:09:42 +01:00
Stefan Haller
9de8d17d84 Don't show error toast for disabled keybindings if DisabledReason text is empty
This makes it possible to "silently" disable a keybinding. The effect is the
same as putting the check in the handler and returning nil from there, except
that doing it this way also hides it from the bottom line if DisplayOnScreen is
true.
2025-01-03 10:09:42 +01:00
Jesse Duffield
9776be3131 Tweak file icons (#4145)
YML icon should be purple, and folder icon should be grey

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 15:39:43 +11:00
Jesse Duffield
7f7d9b166f Tweak file icons
YML icon should be purple, and folder icon should be grey
2025-01-03 15:29:20 +11:00
Jesse Duffield
3dd2e25dfa Clarify commit message prefix mechanics (#4114)
- **PR Description**
Added quote that qlarifies that users should use subgroups instead of
regular match when configuring commit message prefixes

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:29:52 +11:00
ZeroMask
9790a7e00c docs: qlarify commit message prefix mechanics
Added quote that qlarifies that users should use subgroups instead of regular match when configuring commit message prefixes
2025-01-03 14:22:02 +11:00
Jesse Duffield
a5c6a6120d documentation - describe os.openLink (#3094)
- this helps to solve issues as in #3052
- provide an example of how to pass a link to a bash script

- **PR Description** 

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:12:44 +11:00
Sebastian Mangelsen
bf9f9b6c04 provide section for openLink
- this helps to solve issues as in #3052
- provide an example of how to pass it
  to a bash script
2025-01-03 14:07:30 +11:00
Jesse Duffield
d520d5e404 Bump crypto and net packages (#4144)
The old versions had some CVEs which I'm almost certain were not
relevant to lazygit but this means I get to close a couple PRs easily.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-03 14:07:12 +11:00
Jesse Duffield
3241a9c251 Bump crypto and net packages
The old versions had some CVEs which I'm almost certain were not
relevant to lazygit but this means I get to close a couple PRs easily.
2025-01-03 14:01:26 +11:00
Jesse Duffield
4c4a2c3ff4 Fix typos (#3920)
Just thought I'd contribute some typo fixes that I stumbled on. Nothing
controversial (hopefully).

Use the following command to quickly review the corrections made:
```shell
git diff HEAD^! --word-diff-regex='\w+' -U0 \
  | grep -E '\[\-.*\-\]\{\+.*\+\}' \
  | sed -r 's/.*\[\-(.*)\-\]\{\+(.*)\+\}.*/\1 \2/' \
  | sort | uniq -c | sort -n
```

FWIW, the typos are:
* commitable -> committable (x8)
* uncommited -> uncommitted (x3)
* uniquefy -> uniquify
* acccordion -> accordion
* integrationt -> integration
* nicers -> nicer
* existant -> existent
* potentiall -> potentially
* subling -> sibling
* supporta -> supports
* unbenownst -> unbeknownst
* worktre -> worktree
2025-01-03 10:57:10 +11:00
Nathan Baulch
508cdb40a8 Fix typos 2025-01-03 10:50:36 +11:00
Jesse Duffield
ae459b2377 chore: use errors.New to replace fmt.Errorf with no parameters (#4107)
use errors.New to replace fmt.Errorf with no parameters
2025-01-03 10:33:39 +11:00
RiceChuan
c834e132c7 chore: use errors.New to replace fmt.Errorf with no parameters
Signed-off-by: RiceChuan <lc582041246@gmail.com>
2025-01-02 17:27:54 +11:00
Jesse Duffield
5e9ba82d7b Add worktree option to fast forwarding operation (#4051)
- **PR Description**

Fix a reported issue regarding Fast-forwarding a branch that is checked
out in a different worktree. It's reported, and I could
[repro](https://github.com/jesseduffield/lazygit/issues/2957#issuecomment-2462872838),
that whenever such an action is taken, the current worktree is polluted
with unwanted File changes related to the Fast-forward operation.

A solution is suggested – and tested to produce expected results – that
adding `--work-tree` option to the generated command should fix the
issue.

[Issue: 2957](https://github.com/jesseduffield/lazygit/issues/2957)

I'm proposing to merge these changes as it produces expected results:
<img width="1722" alt="Screenshot 2024-11-08 at 19 55 31"
src="https://github.com/user-attachments/assets/89ac1c8d-7a64-4d88-afd9-3ec3d41705f1">



- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 17:25:43 +11:00
John Mutuma
fc78082e81 Formatting the file with gofumpt 2025-01-02 16:52:24 +11:00
John Mutuma
d7d5733a71 Revert unwanted change 2025-01-02 16:52:24 +11:00
John Mutuma
5240b2862f Add worktree option to fast forwarding operation 2025-01-02 16:52:24 +11:00
John Mutuma
e1c18226bf Add worktree option to fast forwarding operation 2025-01-02 16:52:24 +11:00
Jesse Duffield
c4e59aea66 Update docs to describe use of custom commands without keybindings (#3846)
- **PR Description**

Update custom command documentation to describe how commands can be used
without keybindings (see [issue
3799](https://github.com/jesseduffield/lazygit/issues/3799#issuecomment-2297999051))

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2025-01-02 16:50:32 +11:00
A. Jensen
75311750c8 update documentation to describe use of custom commands without keys specified. 2025-01-02 16:50:26 +11:00
Jesse Duffield
16a158a025 Default to half-screen mode when opening with certain CLI args (#4141)
It should have been half-screen from the get-go. I think I just used
full-screen to make demos look nicer. Now that we have a CLI arg for the
screen mode we can make use of that in the demos.

Relates to https://github.com/jesseduffield/lazygit/issues/3042

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 16:44:25 +11:00
Jesse Duffield
621229bb09 Default to half-screen mode when filtering files or using the git-arg CLI arg
It should have been half-screen from the get-go. I think I just used
full-screen to make demos look nicer. Now that we have a CLI arg for the
screen mode we can make use of that in the demos.
2025-01-02 16:10:58 +11:00
Jesse Duffield
536ef82866 Add screen-mode command line argument (#4103)
Introduce a new "screen-mode" command line argument (`-sm
normal|half|full` / `--screen-mode normal|half|full`) that allows a user
to specify which screen mode (normal, half or full) Lazygit should use
when it runs.

This argument will take precedence over a default Window Size specified
in user config.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 16:09:09 +11:00
Alex Lewis
54680e0836 Add screen-mode command line argument
Introduce a new "screen-mode" command line argument that allows a user
to specify which screen mode (normal, half or full) Lazygit should use
when it runs.

This argument will take precedence over a default Window Size specified
in user config.
2025-01-02 16:01:48 +11:00
Jesse Duffield
fc69945a80 Update instructions for using OSC52 with tmux (#3597)
- **PR Description**
Update the instructions on using copyToClipboardCmd config to copy using
OSC52 with tmux

Added `-w 0` flag to `base64` command because it wraps lines that are
longer than 76 by default, [that fails to copy on some terminal
emulators](https://github.com/jesseduffield/lazygit/issues/3595).

We compare `$TERM` to `^(screen|tmux)` because both of them are valid as
[per the manual](https://man7.org/linux/man-pages/man1/tmux.1.html):
```
default-terminal terminal
               Set the default terminal for new windows created in this
               session - the default value of the TERM environment
               variable.  For to work correctly, this must be set to
               ‘screen’, ‘tmux’ or a derivative of them.
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`) -- not
relevant
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
-- not relevant
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide) -- not relevant
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
-- not relevant
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:47:34 +11:00
Elias Assaf
69a048c0ff Update instructions for using OSC52 with tmux
Signed-off-by: Elias Assaf <elyas51000@gmail.com>
2025-01-02 15:47:27 +11:00
Jesse Duffield
6c6d835d50 Set repology table to 3 columns (#4138)
- **Set repology table to 3 columns on the README file because a single
column takes too much vertical space**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:41:40 +11:00
hasecilu
2a72e96011 Set repology table to 3 columns 2025-01-02 15:41:29 +11:00
Jesse Duffield
a507c836b2 enhancement: Use HEX colors on file icons instead of C256 colors (#4029)
- **PR Description**
Lazygit already accepts to customize UI colors using HEX values but the
color of the icons still were using C256 notation, this PR makes the
change to use HEX values. Not sure if there is a special reason to not
make the change.

You can create the available files with:
```shell
touch _gvimrc _vimrc bin brewfile bspwmrc build build.gradle build.zig.zon cantorrc Cargo.lock Cargo.toml checkhealth cmakelists.txt CODE-OF-CONDUCT.md CODE_OF_CONDUCT CODE_OF_CONDUCT.md COMMIT_EDITMSG commit_editmsg commitlint.config.js commitlint.config.ts compose.yaml compose.yml config containerfile copying copying.lesser docker-compose.yaml docker-compose.yml dockerfile Dockerfile ds_store eslint.config.cjs eslint.config.js eslint.config.mjs eslint.config.ts ext_typoscript_setup.txt favicon.ico fn fp-info-cache fp-lib-table FreeCAD.conf gemfile$ gitignore_global gnumakefile GNUmakefile go.mod go.sum go.work gradle gradle-wrapper.properties gradle.properties gradlew gruntfile.babel.js gruntfile.coffee gruntfile.js gruntfile.ls gruntfile.ts gtkrc gulpfile.babel.js gulpfile.coffee gulpfile.js gulpfile.ls gulpfile.ts hidden hypridle.conf hyprland.conf hyprlock.conf hyprpaper.conf i3blocks.conf i3status.conf include ionic.config.json justfile kalgebrarc kdeglobals kdenlive-layoutsrc kdenliverc kritadisplayrc kritarc lib LICENSE LICENSE.md localized lxde-rc.xml lxqt.conf Makefile mix.lock mpv.conf node_modules npmignore nuxt.config.cjs nuxt.config.js nuxt.config.mjs nuxt.config.ts package-lock.json package.json PKGBUILD platformio.ini pom.xml prettier.config.cjs prettier.config.js prettier.config.mjs prettier.config.ts PrusaSlicer.ini PrusaSlicerGcodeViewer.ini py.typed QtProject.conf R robots.txt rubydoc SECURITY SECURITY.md settings.gradle strings svelte.config.js sxhkdrc sym-lib-table tailwind.config.js tailwind.config.mjs tailwind.config.ts tmux.conf tmux.conf.local tsconfig.json unlicense vagrantfile$ vlcrc webpack weston.ini workspace xmobarrc xmobarrc.hs xmonad.hs xorg.conf xsettingsd.conf yarn.lock 

```
and 
```shell
touch f.{cmake,3gp,3mf,7z,a,aac,ai,aif,aiff,android,ape,apk,app,apple,applescript,asc,ass,astro,avi,avif,avro,awk,azcli,bak,bash,bash_history,bash_pro,bashrc,bat,bats,bazel,bib,bicep,bicepparam,bladephp,blend,blp,bmp,brep,bz,bz2,bz3,bzl,c,c++,cab,cache,cast,cbl,cc,ccm,cfg,cjs,class,clj,cljc,cljd,cljs,cls,cmake,cmd,cob,cobol,coffee,conf,configru,cp,cpio,cpp,cppm,cpy,cr,crdownload,cs,csh,cshtml,cson,csproj,css,csv,csx,cts,cu,cue,cuh,cxx,cxxm,d,dts,dart,db,dconf,deb,desktop,diff,djvu,dll,doc,docx,dot,download,drl,dropbox,ds_store,DS_store,dump,dwg,dxf,ebook,ebuild,editorconfig,edn,eex,ejs,el,elc,elf,elm,eln,env,eot,epp,epub,erb,erl,ex,exe,exs,f#,f3d,f90,fbx,fcbak,fcmacro,fcmat,fcparam,fcscript,fcstd,fcstd1,fctb,fctl,fdmdownload,fish,flac,flc,flf,flv,fnl,font,fs,fsi,fsscript,fsx,gcode,gd,gdoc,gem,gem,gemspec,gform,gif,git,glb,gnumake,go,godot,gql,gradle,graphql,gresource,groovy,gsheet,gslides,guard,gv,gz,h,haml,hbs,hc,heex,hex,hh,hpp,hrl,hs,htm,html,huff,hurl,hx,hxx,ical,icalendar,ico,ics,ifb,ifc,ige,iges,igs,image,img,iml,import,info,ini,ino,ipynb,iso,ixx,j2c,j2k,jad,jar,java,jfi,jfif,jif,jl,jmd,jp2,jpe,jpeg,jpg,jpx,js,json,json5,jsonc,jsx,jwmrc,jxl,kbx,kdb,kdbx,kdenlive,kdenlivetitle,kicad_dru,kicad_mod,kicad_pcb,kicad_prl,kicad_pro,kicad_sch,kicad_sym,kicad_wks,ko,kpp,kra,krz,ksh,kt,kts,latex,lck,leex,less,lff,lhs,license,liquid,localized,lock,log,lrc,lua,luac,luau,lz,lz4,lzh,lzma,lzo,m,m3u,m3u8,m4a,m4v,magnet,make,markdown,material,md,md5,mdx,mint,mjs,mk,mkd,mkv,ml,mli,mm,mo,mobi,mojo,mov,mp3,mp4,mpp,msf,msi,mts,mustache,nfo,nim,nix,node,npmignore,nswag,nu,o,obj,odp,ods,odt,ogg,ogv,opus,org,otf,out,part,patch,pck,pdf,php,pl,pls,ply,pm,png,po,pot,pp,ppt,pptx,prisma,pro,proc,properties,ps1,psb,psd,psd1,psm1,pub,pxd,pxi,pxm,py,pyc,pyd,pyi,pyo,pyw,pyx,qm,qml,qrc,qss,query,r,rake,rake,rar,razor,rb,rdata,rdb,rdoc,rds,readme,res,resi,rlib,rmd,rpm,rproj,rs,rspec,rspec_parallel,rspec_status,rss,rtf,ru,rubydoc,sass,sbt,sc,scad,scala,scm,scss,sh,sha1,sha224,sha256,sha384,sha512,shell,sig,signature,skp,sldasm,sldprt,slim,sln,slvs,sml,so,sol,specjs,specjsx,spects,spectsx,sql,sqlite,sqlite3,srt,ssa,ste,step,stl,stp,strings,sty,styl,stylus,sub,sublime,suo,sv,svelte,svg,svh,swift,t,tar,taz,tbc,tbz,tbz2,tcl,templ,terminal,testjs,testjsx,testts,testtsx,tex,tf,tfvars,tgz,tiff,tlz,tmux,toml,torrent,tres,ts,tscn,tsconfig,tsv,tsx,ttf,twig,txt,txz,typoscript,tz,tzo,ui,v,vala,vh,vhd,vhdl,video,vim,vsh,vsix,vue,war,wasm,wav,webm,webmanifest,webp,webpack,windows,wma,woff,woff2,wrl,wrz,wv,wvc,x,xaml,xcf,xcplayground,xcstrings,xhtml,xls,xlsx,xm,xml,xpi,xul,xz,yaml,yml,zig,zip,zsh,zsh-theme,zshrc,zst,strings}
```
to check the new colors.

Some icons could have be changed because I compared againa
nvim-web-devicons file.

Let me know if you want to change some icon or color.


**Edit**: I added 2 new commits that use glyphs from Nerd Fonts 3.3.0

---

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [X] 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)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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))
* [x] Docs have been updated if necessary
* [X] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:41:16 +11:00
hasecilu
8b90cca521 Use HEX colors on file icons instead of C256 colors 2025-01-02 15:36:27 +11:00
Jesse Duffield
3573289452 Update chinese translation for pull requests (#4140)
- **PR Description**

Based on https://github.com/jesseduffield/lazygit/pull/3246

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:33:18 +11:00
Jesse Duffield
87b54a4107 Update chinese translation for pull requests 2025-01-02 15:26:42 +11:00
Jesse Duffield
1b0d3829f8 Allow on prem Azure DevOps Server pull request (#3954)
- **PR Description**

Allows creating a pull request for an on prem Azure DevOps Server

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-02 15:17:58 +11:00
Wayne Bowie
aad3dc42a7 Allow on prem Azure DevOps Server pull request 2025-01-02 15:10:02 +11:00
Stefan Haller
f884cc2af9 Allow to switch branches in Commit View (#4115) (#4117)
- **PR Description**

When the user checks out a commit which has a local branch ref attached
to it, they can select between checking out the branch or checking out
the commit as detached head. If no local branch is attached to the
commit, the behavior is like before: They are asked to confirm, if they
want to checkout the commit as detached head.

Requested in #4115.

Note: I tried also to consider remote branches, but because I wasn't
able to correlate remote branches to their commits, I deferred it and
leave it open for later improvement.
2025-01-01 14:59:20 +01:00
Sebastian Flügge
f4c8287143 Allow to switch branches in Commit View
When the user checks out a commit which has a local branch ref attached
to it, they can select between checking out the branch or checking out
the commit as detached head.
2025-01-01 14:55:12 +01:00
Jesse Duffield
03d7bc854e Bump kill package (#4137)
Closes https://github.com/jesseduffield/lazygit/issues/3008

This should reduce the instances of killing random processes on windows.

See https://github.com/jesseduffield/kill/pull/1

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2025-01-01 23:56:58 +11:00
Jesse Duffield
fdf1643f63 Bump kill package
This should reduce the instances of killing random processes on windows.

See https://github.com/jesseduffield/kill/pull/1
2025-01-01 23:45:53 +11:00
Stefan Haller
d93be027b6 docs: Stylize and correct the NixOS section in README.md (#4135)
- **PR Description**

configuration.nix is a file, and most files in the README.md are
stylized as code blocks. `environment.systemPackages` is actually just a
code block, and should be stylized as such.
2025-01-01 13:11:15 +01:00
wadsaek
fd5be11370 Stylize and correct the NixOS section in README.md
configuration.nix is a file, and most files in the README.md are
stylized as code blocks. `environment.systemPackages` is actually just a
code block, and should be stylized as such
2025-01-01 12:48:19 +02:00
Jesse Duffield
1e1fba4ce6 Add vision and design principles doc (#4053)
I want to spell out the design principles behind Lazygit so that our
priorities are clear and it's easier to make UX decisions (especially
for early contributors).

It's not possible to codify this in a way that will resolve all disputes
but I think it's worthwhile to enumerate some of the things that keep
coming up in our discussions about X or Y feature.

This is a very rough draft (effectively a brain-dump). So I expect
plenty of feedback :)

CC @stefanhaller @karimkhaleel @mark2185 @afhoffman @AzraelSec

- **Please check if the PR fulfills these requirements**

* [ ] Docs have been updated if necessary
2024-12-31 16:53:23 +11:00
Jesse Duffield
b174791490 Add vision and design principles doc
I want to spell out the design principles behind lazygit so that our priorities are clear
and it's easier to make UX decisions
2024-12-31 16:50:06 +11:00
Stefan Haller
a4ecd293f9 Fix hang when returning from shell command (#4126)
- **PR Description**

In #3793 we changed the execution of shell commands to use an
interactive shell (-i), because this allows users to use aliases or
shell functions, which is a nice convenience.

Since then, however, many users have reported problems with lazygit not
coming back to the foreground after executing a shell command. Some
users report that appending "; exit" to the end of the command line
solves this. I don't really understand what the cause of this problem
was, or why appending "; exit" solves it, but if it helps, let's do it.

Fixes #3903, #3923, #3937.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-28 14:56:54 +01:00
Stefan Haller
5fac40c129 Fix hang when returning from shell command
In 5a3049485c we changed the execution of shell commands to use an interactive
shell (-i), because this allows users to use aliases or shell functions, which
is a nice convenience.

Since then, however, many users have reported problems with lazygit not coming
back to the foreground after executing a shell command. Some users report that
appending "; exit" to the end of the command line solves this. I don't really
understand what the cause of this problem was, or why appending "; exit" solves
it, but if it helps, let's do it.
2024-12-28 14:53:57 +01:00
Stefan Haller
ec410b2ae6 Don't preserve commit message when it's unchanged from initial message (#4110)
- **PR Description**

Sometimes we populate the commit message panel with a pre-created commit
message. The two cases where this happens is:
- you type `w` to commit, in which case we put the skipHookPrefix in the subject
- you have a commitPrefix pattern, in which case we match it against the branch
  name and populate the subject with the replacement string if it matches

In either case, if you have a preserved commit message, we use that.

Now, when you use either of these and then cancel, we preserve that initial,
unchanged message and reuse it the next time you commit. This has two problems:
it strips spaces, which is a problem for the commitPrefix patterns, which often
end with a space. And also, when you change your config to experiment with
commitPrefix patterns, the change seemingly doesn't take effect, which can be
very confusing.

To fix both of these problems, only preserve the commit message when it is not
identical to the initial message.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-23 12:32:12 +01:00
Stefan Haller
3a30211099 Don't preserve commit message when it's unchanged from initial message
Sometimes we populate the commit message panel with a pre-created commit
message. The two cases where this happens is:
- you type `w` to commit, in which case we put the skipHookPrefix in the subject
- you have a commitPrefix pattern, in which case we match it against the branch
  name and populate the subject with the replacement string if it matches

In either case, if you have a preserved commit message, we use that.

Now, when you use either of these and then cancel, we preserve that initial,
unchanged message and reuse it the next time you commit. This has two problems:
it strips spaces, which is a problem for the commitPrefix patterns, which often
end with a space. And also, when you change your config to experiment with
commitPrefix patterns, the change seemingly doesn't take effect, which can be
very confusing.

To fix both of these problems, only preserve the commit message when it is not
identical to the initial message.
2024-12-23 12:28:52 +01:00
Stefan Haller
ec92d92bf4 Extend commitPrefix test to cancel without changing the commmit message
The test shows that we lose a space when cancelling and committing again.
2024-12-23 12:28:52 +01:00
Stefan Haller
87d5da511e Cleanup: reformat to make the test setup code easier to read
- break it to separate lines
- use backticks for pattern so we need less quoting
- don't unnecessarily quote forward slash in pattern
2024-12-23 12:28:52 +01:00
Stefan Haller
e29ddf46d2 Wrap lines in staging view (#4098)
- **PR Description**

Add a user config (on by default) to turn on line wrapping in the
staging view (and custom patch building view).

Fixes #3558.

This is a bit of a longer PR because I had to fix a bunch of things to
make this possible, and because it takes much more than just turning on
`Wrap` on the staging view.

Usually when I make changes to gocui I include them in the lazygit PR
for easier review; this time, however, the changes required touching
gocui's tests, which are not included in our vendored copy, so I made a
[PR in gocui](https://github.com/jesseduffield/gocui/pull/67) to be
reviewed there, and only included the squashed changes here.

Hot-reloading of the new user config is not perfect: if the staging view
is focused, you need to escape out of it and enter it again for the
change to take affect. I wasn't sure it's worth adding code to fix this.

As for tests: I didn't find a way to add an integration test for this,
as the view geometry is not fixed when you run them locally. But I
didn't look into this very deeply.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-23 12:27:34 +01:00
Stefan Haller
15288b7bf4 Add user config to enable line wrapping in the staging view
It is enabled by default, because I think it's often helpful, and rarely in the
way. I bet most user won't even notice.
2024-12-23 12:24:09 +01:00
Stefan Haller
2828fb94fb Rewrap patch when view width changes
This makes it so that when the staging view is resized, we keep the same patch
line selected (as opposed to the same view line, which may correspond to a
different patch line after resizing). It doesn't seem like a terribly important
feature for resizing the window, but it is essential when initially entering the
staging view: we select the first line of the first hunk in this case, but we do
that before layout runs. At layout time the view is then split into
unstaged/staged changes, and if this split is horizontal, the view gets narrower
and may be wrapped in a different way. With this commit we ensure that the first
line of the first hunk is still selected after that.
2024-12-23 12:24:09 +01:00
Stefan Haller
5213a9de32 Handle wrapped lines in patch explorer state
So far, lines in the view corresponded 1:1 to lines in the patch. Once we turn
on wrapping for the staging view (which we don't do yet), this is no longer
true, so we need to convert from view lines to patch lines or vice versa all
over the place.
2024-12-23 12:24:09 +01:00
Stefan Haller
b7444b9a49 Return arrays with line indices from WrapViewLinesToWidth
This makes it easy to convert an original line index to a wrapped line index, or
vice versa.
2024-12-23 12:24:09 +01:00
Stefan Haller
5d3b3c6656 Extract helper function
This doesn't improve the code much in the current state, but we'll add some more
code to this helper function in the next commit, which makes it worth it.
2024-12-23 12:24:09 +01:00
Stefan Haller
65a28c4c3b Convert tabs to spaces in WrapViewLinesToWidth
We haven't needed this before since we were only using the function for text in
confirmations and menus, which is unlikely to contain tabs. We are going to use
it for patches in the staging view though, which often do.
2024-12-23 12:24:09 +01:00
Stefan Haller
1f2cb35cc9 Refactor: move wrapMessageToWidth to utils/lines.go
to make it more generally usable by clients other than ConfirmationHelper, which
we will do later in this branch. Rename it to WrapViewLinesToWidth while we're
at it.

Add tests; in particular, add a sanity check that we wrap lines the same way as
gocui does. The tests that are added here are the same ones as in gocui for its
lineWrap function, but we'll extend them a bit in later commits in this branch.
2024-12-23 12:24:09 +01:00
Stefan Haller
2b49865d0d Fix: set state to nil when patch building view loses focus
This is also what we do in the staging controller, and it makes it so that when
you exit the patch building view and then enter it again (for another file, or
the same one) we select the first hunk again.
2024-12-23 12:24:09 +01:00
Stefan Haller
da47498066 Cleanup: remove unused log parameter of patch_exploring.NewState 2024-12-23 12:24:09 +01:00
Stefan Haller
2f1564d288 Cleanup: remove unused method RangeStartLineIdx 2024-12-23 12:24:09 +01:00
Stefan Haller
3610f13418 Fix several bugs in wrapMessageToWidth
This corresponds to the following fixes in gocui's lineWrap function:
- https://github.com/jesseduffield/gocui/pull/67/commits/86cf561ef493
- https://github.com/jesseduffield/gocui/pull/67/commits/24746d5cd6ee
- https://github.com/jesseduffield/gocui/pull/67/commits/4b97941c4ec6
2024-12-23 12:24:09 +01:00
Stefan Haller
2417b70acd Bump gocui 2024-12-23 12:24:09 +01:00
Stefan Haller
b61c395278 Fix moving a commit across a branch boundary in a stack of branches (#4096)
- **PR Description**

When moving the first commit of the second branch in a stack down by one
(across the branch head of the first branch), the current behavior is
broken: we move the commit only past the update-ref todo of branch1,
which means the order of commits stays the same and only the branch head
icon moves up by one. However, we move the selection down by one, so the
wrong commit is selected now. This is especially bad if you type a bunch
of ctrl-j quickly in a row, because now you are moving the wrong commit.

There would be two possible ways to fix this:
1) keep the moving behavior the same, but don't change the selection
2) change the behavior so that we move the commit not only past the
update-ref, but also past the next real commit.

You could argue that 1) is the more desirable fix, as it gives you more
control over where exactly the moved commit goes; however, it is much
trickier to implement, so we go with 2) for now. If users need more
fine-grained control, they can always enter an interactive rebase first.

While we're at it, also fix moving a commit across an exec todo in an
interactive rebase, which is currently broken (it moves the commit one
too far).

Fixes #4040.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-23 12:20:47 +01:00
Stefan Haller
a9ef69b9c7 Fix moving a commit across a branch boundary in a stack
See the previous commit for a detailed explanation.
2024-12-23 12:18:48 +01:00
Stefan Haller
cf27974ea3 Add test for moving a commit across a branch boundary in a stack
The test demonstrates that the behavior is undesirable right now: we move the
commit only past the update-ref todo of branch1, which means the order of
commits stays the same and only the branch head icon moves up by one. However,
we move the selection down by one, so the wrong commit is selected now. This is
especially bad if you type a bunch of ctrl-j quickly in a row, because now you
are moving the wrong commit.

There are two possible ways to fix this:
1) keep the moving behavior the same, but don't change the selection
2) change the behavior so that we move the commit not only past the update-ref,
   but also past the next real commit.

You could argue that 1) is the more desirable fix, as it gives you more control
over where exactly the moved commit goes; however, it is much trickier to
implement, so we go with 2) for now (and that's what the commented-out
"EXPECTED" section documents here). If users need more fine-grained control,
they can always enter an interactive rebase first.
2024-12-23 12:18:48 +01:00
Stefan Haller
83356d441f Fix moving a commit across an exec todo 2024-12-23 12:18:48 +01:00
Stefan Haller
49c50fc95c Add tests for moving across an exec todo
These don't work correctly yet, they move it one too far.
2024-12-23 12:18:48 +01:00
Stefan Haller
b719dc4d8e Add tests for moving a commit across an update-ref todo
This works correctly, we just didn't have test coverage for it.
2024-12-23 12:18:48 +01:00
Stefan Haller
75121384a3 Drop merge commits (#4094)
- **PR Description**

Allow deleting a merge commit. We only allow this when the merge commit
is the only selected item, and only outside of a rebase. The reason for
this is that we don't show the "label" and "reset" todos in lazygit, so
deleting a merge commit would leave the commits from the branch that is
being merged in the list as "pick" commits, with no indication that they
are going to be dropped because they are on a different branch, and the
merge commit that would have brought them in is gone. This could be very
confusing.

Fixes #3164.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-23 12:17:26 +01:00
Stefan Haller
078445db63 Allow deleting a merge commit
For non-merge commits we change "pick" to "drop" when we delete them. We do this
so that we can use the same code for dropping a commit no matter whether we are
in an interactive rebase or not. (If we aren't, we could just as well delete the
pick line from the todo list instead of setting it to "drop", but if we are, it
is better to keep the line around so that the user can change it back to "pick"
if they change their mind.)

However, merge commits can't be changed to "drop", so we have to delete them
from the todo file. We add a new daemon instruction that does this.

We still don't allow deleting a merge commit from within an interactive rebase.
The reason is that we don't show the "label" and "reset" todos in lazygit, so
deleting a merge commit would leave the commits from the branch that is being
merged in the list as "pick" commits, with no indication that they are going to
be dropped because they are on a different branch, and the merge commit that
would have brought them in is gone. This could be very confusing.
2024-12-23 12:12:45 +01:00
Stefan Haller
64eb3d560b Simplify finding rebase todos
One of the comments we are deleting here said:

  // Comparing just the hash is not enough; we need to compare both the
  // action and the hash, as the hash could appear multiple times (e.g. in a
  // pick and later in a merge).

I don't remember what I was thinking when I wrote this code, but it's nonsense
of course. Maybe I was thinking that the hash that appears in a "merge" todo
would be the hash of the commit that is being merged in (which would then
actually appear in an earlier pick), but it isn't, it's the hash of the merge
commit itself (so that the rebase can reuse its commit message). Which means
that hashes are unique, no need to compare the action.
2024-12-23 12:12:45 +01:00
Stefan Haller
2823a7cff0 Make equalHash more correct
So far it didn't have to handle the case where one hash is empty and the other
isn't, but in the next commit we need that, so let's handle that case correctly.
There's enough logic in the function now that it's worth covering it with tests.
2024-12-23 12:12:45 +01:00
Stefan Haller
d5f2fb6003 Disable dropping merge commits if it's not a single selection 2024-12-23 12:12:45 +01:00
Stefan Haller
bd0d9ef259 Disable fixup/squash for merge commits 2024-12-23 12:12:45 +01:00
Stefan Haller
75d2fb1df2 Disable moving merge commits
Not much of a change in behavior, because moving merge commits was already not
possible. However, it failed with a cryptic error message ("Todo fa1afe1 not
found in git-rebase-todo"), so disable it properly instead.
2024-12-23 12:12:45 +01:00
Stefan Haller
13e9e1de83 Fix typos (#4121)
- **PR Description**

This PR fixes typos in the `allBranchesLogCmd` description
2024-12-18 14:17:28 +01:00
Sergey Kochetkov
93a37cf83e fix(config): allBranchesLogCmd description typo 2024-12-18 11:42:50 +01:00
Stefan Haller
0f269183de remove duplicate secondary MouseWheelUp keybind (#4120)
- **Remove duplicate secondary view MouseWheelUp keybinding**

The `MouseWheelUp` keybind for the secondary view was duplicated in the
array.
2024-12-17 22:46:27 +01:00
Samuel Dominguez
4268701606 reorder keybinds to main/down, main/up, secondary/down, secondary/up 2024-12-17 16:57:23 +00:00
Samuel Dominguez
799827ee0e remove duplicate secondary MouseWheelUp keybind 2024-12-17 14:00:21 +00:00
Stefan Haller
4a7cf6040e Show the number of lines changed per file in working file tree view (#4015)
- **PR Description**
Implements Issue #3643
Adds the number of line changes to the end of each file line in the
Files view.
Also adds the possibility for the user to enable and disable this
feature through the UserConfig.
<img width="323" alt="screenshot"
src="https://github.com/user-attachments/assets/6f818dd4-fbf5-49f2-b338-1b1fcc73f73a">

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [x] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-08 12:14:06 +01:00
johannaschwarz
f455f99705 Add user config gui.showNumstatInFilesView
When enabled, it adds "+n -m" after each file in the Files panel to show how
many lines were added and deleted, as with `git diff --numstat` on the command
line.
2024-12-08 12:09:47 +01:00
Stefan Haller
f3a5c184e1 Fix issues with opening links and files using WSL (#3850)
- **PR Description**

This PR fixes to issues with the current implementation of the OSConfig
for WSL:

**File explorer**
When using the file explorer from WSL, for instance by pressing "o" in
the "Files" menu, the explorer always opens on the default landing page.
This is caused by the filepath being expressed in WSL format instead of
the expected Windows format. For instance:
- "/home/myuser/path/to/my/file" should be
"\\wsl$\MyDistroName\home\myuser\path\to\my\file"
- "/mnt/c/path/to/my/file" should be "C:\path\to\my\file"

There's a utility to do that in WSL, `wslpath`. We use it in the Open to
format the filename before passing it to the Powershell command

**Link URLs**
Opening links containing ampersands inside lazygit (a pull-request
creation page in BitBucket Server, for instance) returns the following
Powershell error:
> The ampersand (&) character is not allowed. The & operator is reserved
> for future use; wrap an ampersand in double quotation marks ("&") to
> pass it as part of a string.

We fix it by enclosing the URL in single quotes.

**Notes on this PR**
This is my first PR on this repo, please tell me if something is needed.
I read the contributing guide.
The OS-specific logic doesn't appear to be tested in integration and
unit tests, so I didn't add tests.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-04 09:46:28 +01:00
Baptiste Ottino
1543b83d10 Fix opening links containing ampersands (&) in WSL
Opening links containing ampersands inside lazygit (a pull-request
creation page in BitBucket Server, for instance) returns the following
Powershell error:
> The ampersand (&) character is not allowed. The & operator is reserved
> for future use; wrap an ampersand in double quotation marks ("&") to
> pass it as part of a string.

We fix it by enclosing the URL in single quotes.
2024-12-04 09:43:30 +01:00
Baptiste Ottino
4cfeb18632 Fix opening files with explorer in WSL
The OS command to open file in explorer in WSL doesn't currently work as
expected; it always opens the file explorer at the default opening
location. This is because the {{filename}} variable returns the path in
WSL format, and not in the format expected by Windows.

We use wslpath, a utility shipped with WSL, to make the path conversion.
2024-12-04 09:43:30 +01:00
Stefan Haller
3a4422fc68 commits panel: add missing default sort order (#4097)
- **PR Description**

In the commits panel, <c-l> menu has only 3 sort orders, but previously
`git.log.order` had 4 accepted values. `default` is missing in the new
menu.

with `default` selected, I can see `gitlogorder: default` in state.yml
and it function as expected in `lazygit --logs`

```bash
git log HEAD --oneline --pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s --abbrev=40 -300 --no-show-signature -- (145.062786ms)
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-03 09:20:41 +01:00
phanirithvij
6da42b07cd add missing default sort order in commits panel
Signed-off-by: phanirithvij <phanirithvij2000@gmail.com>
2024-12-03 09:56:53 +05:30
Stefan Haller
954347c5bd Use custom context size in range diff (#4082)
- **PR Description**

I just noticed that we don't respect the diff context size when showing
a range diff (both the "sticky" range diff when diffing mode is on, and
the more temporary one when selecting a range of commits). Here's a
quick fix for that.

I was too lazy to add tests for this, let me know if you would find this
important. Right now, it seems we only have tests for the context size
in the staging view, not in any of the other places where diffs can be
shown.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-12-02 10:39:55 +01:00
Stefan Haller
7fb9e8fa9a Respect the diff context size when showing a range diff
This applies to both the "sticky" range diff when diffing mode is on, and the
more temporary one when selecting a range of commits.
2024-12-01 13:01:16 +01:00
Stefan Haller
5cca4c7063 Cleanup: move adding --ignore-all-space arg to DiffCmdObj
It is needed by both call sites of this function. This has the added benefit
that the argument doesn't unnecessarily show up in the status view when diffing
mode is on.
2024-12-01 13:01:15 +01:00
Stefan Haller
53dc23a037 Improve editing a commit (#4090) 2024-12-01 11:08:44 +01:00
Stefan Haller
debfe1a21f Improve editing a commit
In 67b8ef449c we changed the "edit" command to insert a "break" after the
selected commit, rather than setting the selected todo to "edit". The reason for
doing this was that it now works for merge commits too.

Back then, I claimed "In most cases the behavior is exactly the same as before."
Unfortunately that's not true, there are two reasons why the previous behavior
was better (both are demonstrated by tests earlier in this branch):
- when editing the last commit of a branch in the middle of a stack of branches,
  we are now missing the update-ref todo after it, which means that amending the
  commit breaks the stack
- it breaks auto-amending (see the added test earlier in this branch for an
  explanation)

For these reasons, we are going back to the previous approach of setting the
selected commit to "edit" whenever possible, i.e. unless it's a merge commit.

The only scenario where this could still be a problem is when you have a stack
of branches, and the last commit of one of the branches in the stack is a merge
commit, and you try to edit that. In my experience with stacked branches this is
very unlikely, in almost all cases my stacked branches are linear.
2024-12-01 11:05:45 +01:00
Stefan Haller
d84986880e Extract helper methods
We'll reuse them in the next commit.
2024-12-01 11:05:45 +01:00
Stefan Haller
17bb3970c1 Filter out merge commits when generating todo changes in InteractiveRebase
We will need this because under some conditions we are going to use this
function to edit a range of commits, and we can't set merge commits to "edit".
This corresponds to the code in startInteractiveRebaseWithEdit which has similar
logic.

It is a bit unfortunate that we will have these two different ways of setting
todos to edit: startInteractiveRebaseWithEdit does it after stopping in the
rebase, in the Then function of its refresh, but InteractiveRebase does it in
the daemon with a ChangeTodoActionsInstruction. It still makes sense though,
given how InteractiveRebase works.

This not only affects "edit", but also "drop", "fixup", and "squash".
Previously, when trying to use these for a range selection that includes a merge
commit, they would fail with the cryptic error message "Some todos not found in
git-rebase-todo"; now they simply exclude the merge commit. I'm not sure if one
is better or worse than the other, and we should probably simply disable the
commands when a merge commit is selected, but that's out of scope in this PR.
2024-12-01 11:05:45 +01:00
Stefan Haller
016d46526c Add test for editing several commits right after a merge commit
This is very similar to edit_range_select_outside_rebase.go, except that it
selects commits right after, and including, a merge commit.

This test already works correctly. The reason we add it is that we are going to
have two different implementations of the `e` command depending on whether the
last selected commit is a merge commit, and we want to make sure they both work
with a range selection.
2024-12-01 11:05:45 +01:00
Stefan Haller
0766b14afd Add test to auto-amend a commit after pressing e on it
Auto-amending is a little-known feature of git that is very convenient once you
know it: whenever you stop at a commit marked with `edit` in an interactive
rebase, you can make changes and stage them, and when you continue the rebase
they automatically get amended to the commit you had stopped at. This is so
convenient because making changes to a commit is one of the main reasons why you
edit a commit.

Unfortunately this currently doesn't work in lazygit because we don't actually
use `edit` to stop at the first commit (instead, we add a `break` todo after it,
which doesn't have the auto-amend functionality).

We'll improve this later in this branch.
2024-12-01 11:05:45 +01:00
Stefan Haller
4624d496a2 Add test for editing the last commit of a branch in a stack
The test demonstrates that the "update-ref" todo after the selected commit is
missing, which means when we amend the commit it'll break the stack.
2024-12-01 11:05:45 +01:00
Stefan Haller
ea03ae5ee3 Cleanup: remove a no-op Focus() call 2024-12-01 11:05:45 +01:00
Stefan Haller
51e5816dd7 Delete range selection of branches (#4073)
- **PR Description**

This allows range-selecting multiple branches and deleting them all at
once. We allow deleting remote branches (or local and remote branches)
as long as *all* selected branches have one.

We show the warning about force-deleting as soon as at least one of the
selected branches is not fully merged.
2024-12-01 11:02:58 +01:00
Stefan Haller
c1b4201726 Allow deleting a range selection of branches
We allow deleting remote branches (or local and remote branches) only if *all*
selected branches have one.

We show the a warning about force-deleting as soon as at least one of the
selected branches is not fully merged.

The added test only tests a few of the most interesting cases; I didn't try to
cover the whole space of possible combinations, that would have been too much.
2024-12-01 10:59:54 +01:00
Stefan Haller
0b0910573b Extract test helper function checkRemoteBranches
We'll need it a few more times in the next test we add.
2024-12-01 10:59:54 +01:00
Stefan Haller
92bce7de43 Pass a remote branch to ConfirmDeleteRemote
Since we want to select multiselections, this will make it easier to pass a
slice of remote branches. It does require that for the case of the local
branches panel we need to synthesize a RemoteBranch object from the selected
local branch, but that's not hard.
2024-12-01 10:59:54 +01:00
Stefan Haller
e98cc4d016 Extract variables
Besides being a useful cleanup on its own, it will make it easier to support a
multiselection of branches.
2024-12-01 10:59:54 +01:00
Stefan Haller
2ffd52acd1 Fix mouse wheel scrolling of custom patch view (#4089)
- **PR Description**

Mouse wheel scrolling of the custom patch view worked *unless* a file
(as opposed to a directory) is selected in the commit files view.
2024-12-01 10:50:50 +01:00
Stefan Haller
24e98d1792 Fix mouse wheel scrolling of custom patch view
Mouse wheel scrolling of the custom patch view worked *unless* a file (as
opposed to a directory) is selected in the commit files view. The reason was an
obvious typo in the AttachControllers call.
2024-12-01 10:48:27 +01:00
Stefan Haller
a50712b6c2 Cleanup background fetch (#4084) 2024-12-01 10:47:43 +01:00
Stefan Haller
64cebfc0a8 Remove unused texts 2024-12-01 10:44:26 +01:00
Stefan Haller
b07109de4d Remove unused field gui.IsNewRepo 2024-12-01 10:44:26 +01:00
Stefan Haller
59303981f9 Simplify startBackgroundFetch
This code had a lot of logic that (fortunately) didn't work because it was
buggy:

- it was supposed to wait for the auto-fetch delay before fetching for the first
  time in case we start with a repo that we had open in a previous session (i.e.
  that appears in the recent repos list). This code actually ran always, not
  just for known repos, because the IsNewRepo flag is only set later, after this
  function runs. Fortunately, the code didn't work, because time.After starts a
  timer but doesn't wait for it (to do that, it would have to be
  `<-time.After`).
- if the first fetch fails with error 128, it was supposed to show an error
  message and not start the background fetch loop. Fortunately, this didn't work
  because 1) it was guarded by isNew which is always false here, and 2) because
  git's error message in this case is actually "exit code: 128", not "exit
  status 128" (maybe this has changed in git at some point).

I find both of these undesirable. Whenever I open a repo I want an auto-fetch to
be triggered immediately to get my branch information up to date as quickly as
possible. And if the initial fetch fails (e.g. because one of my remotes is
offline or doesn't exist any more), then that's no reason not to start the
auto-fetch loop anyway.

So let's simplify the code to do what it did before, but with much fewer lines
of code.
2024-12-01 10:44:26 +01:00
Stefan Haller
62e31efd0f Saner view geometry (#4085) 2024-12-01 10:43:57 +01:00
Stefan Haller
f6f2a52dee Bump gocui and adapt lazygit code
Original commit message of the gocui change:

This fixes View.Size, Width and Height to be the correct (outer) size of a view
including its frame, and InnerSize/InnerWidth/InnerHeight to be the usable
client area exluding the frame. Previously, Size was actually the InnerSize (and
a lot of client code used it as such, so these need to be changed to InnerSize).
InnerSize, on the other hand, was *one* less than Size (not two, as you would
have expected), and in many cases this was made up for at call sites by adding 1
(e.g. in calcRealScrollbarStartEnd, parseInput, and many other places in the
lazygit code).

There are still some weird things left that I didn't address here:
- a view's lower-right coordinates (x1/y1) are one less than you would expect.
  For example, a view with a 2x2 client area like this:
    ╭──╮
    │ab│
    │cd│
    ╰──╯
  in the top-left corner of the screen (x0 and y0 both zero) has x1/xy at 3, not
  4 as would be more natural.
- a view without a frame has its coordinates extended by 1 on all sides; to
  illustrate, the same 2x2 view as before but without a frame, sitting in the
  top-left corder of the screen, has coordinates x0=-1, y0=-1, x1=2, y1=2. This
  is highly confusing and unexpected.

I left these as they are because they would be even more of a breaking change,
and also because they don't have quite as much of an impact on general app code.
2024-12-01 10:40:08 +01:00
Stefan Haller
579053d5a3 Let schema/config.json end with a line feed (#4092)
- **PR Description**

Some editors add one automatically when saving the file, which causes
confusion and ugly diffs containing `\ No newline at end of file`.
2024-11-30 15:08:28 +01:00
Stefan Haller
10db72d223 Let schema/config.json end with a line feed
Some editors add one automatically when saving the file, which causes confusion
and ugly diffs containing `\ No newline at end of file`.
2024-11-30 15:03:29 +01:00
Jesse Duffield
c3cf48cc49 Allow user to select remote and branch when creating a PR (#1889)
When creating a PR against a selected branch (via O = "create pull
request
options"), the user will first be asked to select a remote (if there is
more
than one). After that, the suggestion area is populated with all remote
branches
at that origin - instead of all local ones. After all, creating a PR
against a
branch that doesn't exist on the remote won't work.

Please note that for the "PR is not filed against 'origin' remote" use
case
(e.g. when contributing via a fork that is 'origin' to a GitHub project
that is
'upstream'), the opened URL will not be correct. This is not a
regression and
will be fixed in an upcoming PR.

Fixes #1826.
2024-11-23 12:10:51 +11:00
Moritz Haase
949e131ebe pkg/gui: Allow user to select remote and branch when creating a PR
When creating a PR against a selected branch (via O = "create pull request
options"), the user will first be asked to select a remote (if there is more
than one). After that, the suggestion area is populated with all remote branches
at that origin - instead of all local ones. After all, creating a PR against a
branch that doesn't exist on the remote won't work.

Please note that for the "PR is not filed against 'origin' remote" use case
(e.g. when contributing via a fork that is 'origin' to a GitHub project that is
'upstream'), the opened URL will not be correct. This is not a regression and
will be fixed in an upcoming PR.

Fixes #1826.
2024-11-23 11:52:21 +11:00
Jesse Duffield
b62546c391 Allow DiffContextSize to be decreased to zero (#4050)
- **PR Description**

Per #4012, the diff context size should be able to be decreased to zero.
I update the type def for DiffContextSize to be an unsigned integer and
add saturated add and subtraction in `context_lines_controller.go` where
the variable is updated (++ or --)

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-11-19 08:27:38 +11:00
LU Jialin
de8dc935a3 use unsigned integer in test and fix CI/linter complaint 2024-11-19 08:21:19 +11:00
LU Jialin
dd765801db add test case for decreasing Diff Context length to zero 2024-11-19 08:21:19 +11:00
LU Jialin
111407d9a6 use an unsigned_64 for DiffContextSize and add saturated add/subtract 2024-11-19 08:21:19 +11:00
Jesse Duffield
9f03f9e95d ci: update upload-artifact and download-artifact actions to v4 (#4063)
- **PR Description**

v3 of `actions/upload-artifact` and `actions/download-artifact` will be
fully deprecated by **5 December 2024**. Jobs that are scheduled to run
during the brownout periods will also fail. See:

1.
https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
2.
https://github.blog/changelog/2024-11-05-notice-of-breaking-changes-for-github-actions/

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-11-17 12:06:22 +11:00
Eng Zer Jun
181b00b758 ci: update upload-artifact and download-artifact actions to v4
v3 of `actions/upload-artifact` and `actions/download-artifact` will be
fully deprecated by 5 December 2024. Jobs that are scheduled to run
during the brownout periods will also fail. See [1][2].

[1]: https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
[2]: https://github.blog/changelog/2024-11-05-notice-of-breaking-changes-for-github-actions/

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2024-11-16 00:42:08 +08:00
Jesse Duffield
e1e4e1be1f Add new filter to only show tracked files in Files panel (#4024)
- **PR Description**

Added new filter to only show tracked files in Files panel. This allows
to hide all non-tracked files on large repos.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->

FYI This is my first PR in this repo.
2024-11-12 17:00:58 +11:00
Yaroslav Veremenko
fdeaf9cea0 Add new filter to only show tracked files in Files panel
This allows to hide all non-tracked files on large repos
2024-11-12 16:54:24 +11:00
Jesse Duffield
b0a766cc95 Fixes to lazygit Ubuntu install instructions in README.md (#3970)
- **PR Description**
Found that the method to pull the latest tarball for the project was
incorrect. This pull request fixes the instructions in the Ubuntu
section of the Readme.

Simple fix to README.md
2024-11-09 18:57:18 +11:00
Stephen Martin
f858460ab9 Fixes to lazygit Ubuntu install instructions in README.md 2024-11-09 18:42:19 +11:00
Jesse Duffield
b2cbd93619 Add config option to disable switching tabs with panel jump keys (#3927)
# **PR Description**

## Problem this PR attempts to solve

I really appreciate the feature added in #3794 that allows switching
tabs using panel jump keys when the side panel is already active and see
how it is convenient for many users. However, after using lazygit for
quite some time, I've developed muscle memory where I rely on pressing a
number key to instantly switch to a panel and perform an action,
regardless of which panel is currently active. I have found myself
several times in the past few days clicking '2' and going to hit 'a' +
'c' to commit all and find I was already had window 2 active and my tab
was instead switched to 'Worktrees' and the keybindings no longer apply
to stage or commit.

## Solution

- Add a config `SwitchTabsWithPanelJumpKeys` as a gui boolean that is
true by default, keeping the current new behavior added by #3794
- When `SwitchTabsWithPanelJumpKeys` is set to false in the user's
config, the old behavior is returned which does not switch tabs using
the side panel jump keys.
- This is behavior is verified with an integration test with
``SwitchTabsWithPanelJumpKeys` set to false that shows the expected
behavior that jumping to window 2 while window 2 is already active does
not switch tabs within window 2

To disable switching tabs with panel jump keys, add the following to
your config.yml:
```yaml
gui:
  # 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
```

### P.S. 
This is my first contribution to lazygit and while I absolutely strived
to read all documentation and follow all standards, I accept that this
PR may not be perfect and am very open to feedback and suggestions to
improve both this code and any future contributions. I absolutely love
lazygit, I use it everyday and swear by it as the most powerful and
efficient tool for managing git, I love and appreciate all the work all
the maintainers do to constantly improve it. So thank you to all who are
reading this and I look forward to contributing more to make lazygit
even more of the best git tool available!

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] No text rendered to user -> Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-11-09 17:23:59 +11:00
Harris Greenstein
8da43af924 Add config option to disable tab switching with jump keys 2024-11-09 17:19:14 +11:00
Jesse Duffield
7edf629eeb Fix installation for Ubuntu in README.md (#4031)
- **PR Description**
If '/usr/local/bin' does not exist, 'install' will eventually result in
a regular file named '/usr/local/bin' being created.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-11-09 17:18:58 +11:00
Shaobo Song
1e8b8471ca Fix installation for Ubuntu in README.md
If '/usr/local/bin' does not exist, 'install' will eventually result
in a regular file named '/usr/local/bin' being created.
2024-11-05 20:52:35 +08:00
Stefan Haller
095eb130e9 Fix scroll position when entering staging view by clicking in the main view (#3992)
This is both a bug fix and a behavior change:

- The bug fix is that when entering the staging view for a selected file
by clicking in the main view, and the main view was scrolled down, then
it would scroll to the top and show an ugly range selection from the
line that was clicked to the line that is now under the mouse after
scrolling up.
- The behavior change is that when leaving the staging view by pressing
escape, it now retains its scroll position rather than scrolling back up
to the top.

In addition, this fixes a minor flickering issue when leaving the
staging view.

Note that maintaining the scroll position when going into and out of the
staging view is not always perfect for two reasons:
- the focused staging view does not wrap long lines, but the unfocused
one does
- a pager like delta might change the number of lines e.g. of the diff
hunks

For the second problem there's little we can do, but the first one will
be improved once we wrap lines in the focused staging view (see #1384
and #3558), which I'm currently working on.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-10-18 22:49:15 +02:00
Stefan Haller
f08b3e9e1d Cleanup: remove isFocused parameter from GetContentToRender and related methods
It became unused in f3eb180f75.
2024-10-18 22:46:48 +02:00
Stefan Haller
8f3e59b78e Don't render staging view when it loses focus
As far as I understand, this was needed back when the staging context was still
responsible for rendering its highlight (as opposed to the gocui view, as it is
today). It was necessary to call it with isFocused=false so that it removed the
highlight. The isFocused bool is no longer used today (and we'll remove it in
the next commit), so there's no need to render the view here any more.

This fixes flickering when leaving the staging view by pressing escape. The
reason is that in this case the patch state was already set to nil by the time
we get here, so we would render an empty view for a brief moment.

On top of that, it fixes unwanted scrolling to the top when leaving the staging
view. The reason for this is that we have code in layout that scrolls views up
if needed, e.g. because the window got taller or the view content got shorter
(added in #3839). This kicked in because we emptied the view, and scrolled it
all the way to the top, which we don't want.
2024-10-18 22:46:47 +02:00
Stefan Haller
eaf3bf0971 Change NewRenderStringWith{out}ScrollTask to reuse the task key of the existing task
This way it won't scroll to the top; we want this when entering the staging
panel or the patch building panel by clicking into the view, and also when
returning from these views by pressing escape. Note that there's a bug in this
latter case: the focused panel still scrolls to the top when hitting escape, we
will fix this in the next commit.

Change it in the same way for NewRenderStringWithScrollTask, just for
consistency, although it's not really necessary there. We use this function only
for focusing the merge conflict view, and in that case we already have an empty
task key before and after, so it doesn't change anything there.
2024-10-18 22:46:47 +02:00
Stefan Haller
4883c867bb Fix non-sticky range select after clicking in staging view (#3998)
- **PR Description**

When clicking in a single-file diff view to enter staging (or custom
patch editing, when coming from the commit files panel), and then
pressing shift-down or shift-up to select a range, it would move the
selected line rather than creating a range. Only on the next press would
it start to select a range from there.

This is very similar to the fix we made for pressing escape in #3828.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-10-18 22:46:27 +02:00
Stefan Haller
a58770ee1b Fix pressing shift-down after clicking in diff view
When clicking in a single-file diff view to enter staging (or custom patch
editing, when coming from the commit files panel), and then pressing shift-down
or shift-up to select a range, it would move the selected line rather than
creating a range. Only on the next press would it start to select a range from
there.

This is very similar to the fix we made for pressing escape in 0e4d266a52.
2024-10-18 10:08:27 +02:00
Stefan Haller
7655f6864e Add test demonstrating a bug with clicking in the staging view
When clicking in the main view to enter staging, and then pressing shift-down to
select a range, it moves the selection rather than selecting a two-line range.
We'll fix this in the next commit.
2024-10-18 10:08:27 +02:00
Stefan Haller
286e5f4849 Fix clicking multiple times in an integration test
So far we only had tests that called Click() only once. If you have a test that
calls Click twice (we'll add one in the next commit), you'll notice that the
second click is interpreted as a drag because the mouse button wasn't released
in between. Fix this by sending a "mouse-up" event after the click.
2024-10-18 10:06:52 +02:00
Stefan Haller
052974be65 Allow pasting commits multiple times (#3983)
- **PR Description**

After pasting commits, hide the cherry-pick status (i.e. remove the "x
commits copied" status in the lower right corner, and hide the blue
selection of the copied commits). However, keep the copied commits
around so that it's possible to paste them again. This can be useful
e.g. to backport a bugfix to multiple major version release branches.

Discussed in #3198.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-10-13 16:59:04 +02:00
Stefan Haller
85523402d6 Allow pasting commits more than once
After pasting commits once, we hide the cherry-picking status (as if it had been
reset), and no longer paint the copied commits with blue hashes; however, we
still allow pasting them again. This can be useful e.g. to backport a bugfix to
multiple major version release branches.
2024-10-13 16:55:54 +02:00
Stefan Haller
f473d23d65 Wrap an overly long line 2024-10-13 16:55:54 +02:00
Stefan Haller
59a937ee7a Get rid of error return value of PostRefreshUpdate and a few related ones
I missed these in https://github.com/jesseduffield/lazygit/pull/3890.
2024-10-13 16:55:54 +02:00
Stefan Haller
53f8249ee1 Fix file icons (#3975)
- **PR Description**

Some file icons weren't drawn correctly, e.g. the ones for
`tailwind.config.ts` or `nuxt.config.ts`, but also many others.

Fixes #3747.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-10-13 16:55:18 +02:00
Stefan Haller
f71274b601 Add test to ensure that file icons are one rune
This should prevent errors like that from happening again.
2024-10-13 16:51:27 +02:00
Stefan Haller
f2fd435c05 Fix many file icons
The string literal "\uf0868" does *not* create a single rune with the code point
f0868, as was intended; instead, it creates two runes, one with the code point
f086, followed by the character '8'.
2024-10-13 16:51:27 +02:00
Stefan Haller
4e361e1a87 Fix merge conflict resolution when file doesn't end with a LF (#3976)
- **PR Description**

When resolving conflicts using lazygit's merge conflicts view in a file
that doesn't end with a trailing line feed, the last line would be lost.

Fixes #3444.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-10-13 16:50:53 +02:00
Stefan Haller
696e78fcc8 Fix ForEachLineInFile to not lose the last line if it doesn't end with a LF 2024-10-09 15:37:08 +02:00
Stefan Haller
b71aa5e23b Add regression test for resolving conflicts in a file without a trailing LF
The test shows that the last line of the file is lost.
2024-10-09 15:36:02 +02:00
Stefan Haller
72cf3efb1d Add test demonstrating problem with ForEachLineInFile
The function drops the last line if it doesn't end with a line feed.
2024-10-09 15:36:02 +02:00
Stefan Haller
ae610dcbb7 Extract helper function for easier testing 2024-10-09 15:08:01 +02:00
Stefan Haller
d11e11d179 Auto-render hyperlinks (#3914)
- **PR Description**

Add a facility to gocui.View to enable auto-rendering of https
hyperlinks. Then, use it for the Command Log panel (as an alternative
approach to #3911), and also in the status view and in confirmation
popups to get rid of some code that used to do this manually.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-09-28 12:07:28 +02:00
Stefan Haller
825f5c0a91 Use AutoRenderHyperLinks in confirmation view
This allows us to get rid of the underlineLinks function.
2024-09-28 12:04:51 +02:00
Stefan Haller
26e3a93fc3 Use AutoRenderHyperLinks in main views
This allows clicking on links in commit messages, for examples. It also affects
the status view, so we can get rid of the manual hyperlinking there.
2024-09-28 12:04:51 +02:00
Stefan Haller
1ceb5a6b37 Turn on AutoRenderHyperLinks in the Command Log panel
Some commands output hyperlinks, and it's useful to be able to click them.
2024-09-28 12:04:51 +02:00
Stefan Haller
65b731f484 Bump gocui 2024-09-28 12:04:51 +02:00
Stefan Haller
c6a7722066 Add a menu item to delete both local and remote branch at once (#3916)
- **PR Description**

Add a menu item to delete both local and remote branch at once.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-09-28 11:26:20 +02:00
Stefan Haller
1ab70ec645 Add a menu item to delete both local and remote branch at once 2024-09-28 11:23:21 +02:00
Stefan Haller
e181de1180 Better branch delete confirmation (#3915)
- **PR Description**

When deleting a local branch, put up the "This branch is not fully
merged, do you want to force delete it" confirmation only when the
branch is not merged into any of the main branches.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-09-28 11:22:54 +02:00
Stefan Haller
c712b1d0fe Better local branch delete confirmation
Currently we try to delete a branch normally, and if git returns an error and
its output contains the text "branch -D", then we prompt the user to force
delete, and try again using -D. Besides just being ugly, this has the
disadvantage that git's logic to decide whether a branch is merged is not very
good; it only considers a branch merged if it is either reachable from the
current head, or from its own upstream. In many cases I want to delete a branch
that has been merged to master, but I don't have master checked out, so the
current branch is really irrelevant, and it should rather (or in addition) check
whether the branch is reachable from one of the main branches. The problem is
that git doesn't know what those are.

But lazygit does, so make the check on our side, prompt the user if necessary,
and always use -D. This is both cleaner, and works better.

See this mailing list discussion for more:
https://lore.kernel.org/git/bf6308ce-3914-4b85-a04b-4a9716bac538@haller-berlin.de/
2024-09-28 11:19:32 +02:00
Stefan Haller
c4e5995cb9 Fix bug with deleting remote branch whose name doesn't match local branch 2024-09-28 11:19:32 +02:00
Stefan Haller
be3683ccc8 Add test that demonstrates bug with deleting remote branch with different name
It's maybe not very common, but it's totally possible for a remote branch to
have a different name than the local branch. This test shows that we don't
support this properly when deleting the remote branch.
2024-09-28 11:19:32 +02:00
Stefan Haller
7e7309f97e Add question marks to questions 2024-09-28 11:19:32 +02:00
Stefan Haller
d2b6f93858 Remove unused texts 2024-09-28 11:19:32 +02:00
Stefan Haller
a91fe517d3 Remove obsolete TODO comment
Looks perfectly internationalized to me.
2024-09-28 11:19:32 +02:00
Stefan Haller
8a328a553a Fix copying commit author to clipboard (#3936)
- **PR Description**

This included single quotes in strange places in the copied text.

Fixes #3933.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-09-28 11:15:03 +02:00
Stefan Haller
3d56357294 Fix copying commit author to clipboard
This was a regression introduced with the GitCommandBuilder in 25f8b0337.
2024-09-23 09:47:14 +02:00
Stefan Haller
9b2a0c4538 Add test for copying a commit author to the clipboard
The test shows that we are including single quotes in strange places.
2024-09-23 09:45:03 +02:00
Jesse Duffield
a04ad24a60 Add performance improvements section to release notes (#3922)
- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-09-18 21:26:47 +10:00
Jesse Duffield
0d633896ae Add performance improvements section to release notes 2024-09-18 21:06:02 +10:00
Stefan Haller
611fabde11 Fix crash when viewing the divergence of a branch which is up to date with its upstream (#3918)
This was introduced by #3838, specifically by commit e675025411.

Fixes #3900 and #3917.
2024-09-18 09:27:11 +02:00
Stefan Haller
f8073c7188 Fix crash when viewing the divergence of a branch which is up to date with its upstream
This was introduced by #3838, specifically by commit e675025411.

Add a regression test that would have crashed without the fix.
2024-09-18 09:24:10 +02:00
Stefan Haller
4dadcd2ace Improve performance with large numbers of untracked or modified files (#3919)
- **PR Description**
**BuildTreeFromFiles** used a linear complexity lookup to find if the
children has already been added. Use maps to get constant time lookup
for children.

For the test scenario in #3798 (90000 untracked files) this reduces the
time of BuildTreeFromFiles from something like 10s down to about 30ms on
my machine.

Fixes #3798.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-09-18 09:23:21 +02:00
partho.kunda
b18f12ca0f Use map to quickly find children in BuildTreeFromFiles 2024-09-18 09:16:58 +02:00
Stefan Haller
c67979abbb Add options for disabling switching to the Files panel after popping or applying a stash (#3913)
- **PR Description**

In v0.44.0 we added a small QoL improvement to auto-switch to the Files
panel after popping or applying a stash. While this should be an
improvement for most people, it turns out to be in the way of some
people's workflows, so make it configurable. See
[here](https://github.com/jesseduffield/lazygit/pull/3888#issuecomment-2350853602)
for more discussion.
2024-09-15 14:19:08 +02:00
Stefan Haller
0e489bb5cc Add options for disabling switching to the Files panel after popping or applying a stash 2024-09-15 11:59:59 +02:00
Stefan Haller
647f533e71 With stacked branches, create fixup commit at the end of the branch it belongs to (#3892)
- **PR Description**

When working with stacked branches, and creating a fixup commit for a
commit in one of the lower branches of the stack, the fixup was created
at the top of the stack and the user needed to move it down to the right
branch manually. This is unnecessary extra work; create it at the end of
the right branch automatically.
2024-09-15 11:21:34 +02:00
Stefan Haller
b22149d832 Create fixup commit at end of its branch when there's a stack of branches 2024-09-15 11:19:39 +02:00
Stefan Haller
396215a5c9 Extract helper function for getting the hash of the last commit made 2024-09-15 11:19:39 +02:00
Stefan Haller
42c157a5e6 Add changeToFixup field to MoveFixupCommitDown 2024-09-15 11:19:39 +02:00
Stefan Haller
a793f709b6 Update language files from Crowdin (#3898)
- **PR Description**

Pull down the latest translations from Crowdin. Unfortunately I forgot
to do this in time for the 0.44 release, bummer.

I'm not sure how much testing/proof-reading/peer review we want to do on
these.
2024-09-15 09:43:15 +02:00
Stefan Haller
f74551e464 Generate keybindings 2024-09-08 15:20:52 +02:00
Stefan Haller
e06b1cef60 Update language files from Crowdin 2024-09-08 15:19:26 +02:00
Stefan Haller
2d0c7cb0fc Switch to Files panel after popping a stash (#3888)
#### PR Description

I find myself always switching to the Files panel after popping a stash,
100% of the time, so it makes sense that lazygit does this for me. Do it
for apply as well, for consistency.

#### Please check if the PR fulfills these requirements

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-09-06 13:21:49 +02:00
Stefan Haller
f5b8619ded Switch to Files panel after popping a stash 2024-09-06 13:15:37 +02:00
Stefan Haller
4c6c915a77 Get rid of a lot of error return values (#3890)
- **PR Description**

Change many functions in the gui package (and some in gocui) to no
longer return errors.

There might be more that could be changed in this way, but I feel these
are the main ones.

Fixes #3887.
2024-09-06 08:48:44 +02:00
Stefan Haller
064fae41e7 Remove return value of OpenCommitMessagePanel
Similar to the previous commit: in 100% of the call sites we now need an extra
`return nil`. Nevertheless, I still prefer it this way.
2024-09-06 08:45:48 +02:00
Stefan Haller
d4ef8e53d5 Remove return value of Alert/Confirm/Prompt
This might seem controversial; in many cases the client code gets longer,
because it needs an extra line for an explicit `return nil`. I still prefer
this, because it makes it clearer which calls can return errors.
2024-09-06 08:45:48 +02:00
Stefan Haller
b15a1c7ae7 Remove return value of CreatePopupPanel 2024-09-06 08:45:48 +02:00
Stefan Haller
6f0182f11c Remove return value of RefreshPatchBuildingPanel 2024-09-06 08:45:48 +02:00
Stefan Haller
371998e635 Remove return value of IContextMgr.Push/Pop et. al. 2024-09-06 08:45:48 +02:00
Stefan Haller
072b465fa6 Fix a lock that is held too long
I can only guess, but I think this was a typo (or a copy-paste-o) when this code
was written. It was introduced in 55af07a1bb, and I think the defer was kept by
accident; if it had been on purpose, then the statement would have been put
right after the Lock call.
2024-09-06 08:45:48 +02:00
Stefan Haller
8302575078 Remove return value of Focus-related functions 2024-09-06 08:45:48 +02:00
Stefan Haller
8edcd71234 Remove return value of IPatchExplorerContext.Render, RenderAndFocus, and NavigateTo 2024-09-06 08:45:48 +02:00
Stefan Haller
5446683881 Remove return value of RenderToMainViews and some related functions 2024-09-06 08:45:48 +02:00
Stefan Haller
b91beb68e1 Remove return value of HandleRender 2024-09-06 08:45:48 +02:00
Stefan Haller
5659f1f3e9 Bump gocui
And adapt client code.
2024-09-06 08:45:48 +02:00
Stefan Haller
753b16b697 Add Zed editor support to editorPreset (#3886)
- **PR Description**

- **Please check if the PR fulfills these requirements**

* [X] 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)
* [X] Docs have been updated if necessary
* [X] You've read through your own file changes for silly mistakes etc
2024-09-03 19:27:29 +02:00
Dmytro Suvorov
da7a28c117 Add Zed to user_config.go and schema 2024-09-03 19:22:56 +02:00
Dmytro Suvorov
c35743d7ad Add Zed to docs/Config.md 2024-09-03 19:22:56 +02:00
Dmytro Suvorov
f0eafabd6d Add Zed support to editor_presets.go 2024-09-03 17:30:56 +03:00
Stefan Haller
fc4cf5d196 Offer autostash option when creating new branch (#3871)
- **PR Description**

Resolves https://github.com/jesseduffield/lazygit/issues/3866

My attempt at creating a shared abstraction felt like it was more
indirection than it was worth so I ended up going with the code
duplication approach.
2024-09-03 09:08:56 +02:00
Brandon
4e880e56c4 Add integration tests for checkout/new branch with autostash 2024-09-03 09:05:53 +02:00
Brandon
e8e39f5ce2 Offer autostash option when creating new branch 2024-09-03 09:05:53 +02:00
Brandon
370ab2d19c Simplify CheckoutRef 2024-09-03 09:05:53 +02:00
Stefan Haller
fa8cd47227 Don't allow opening a menu while the search or filter prompt is open (#3878)
- **PR Description**

This solves several problems that arise from opening a menu while the
prompt is open. We might try to solve these in a different way, e.g. by
dismissing the search prompt before opening a menu, but restricting what
you can do while the prompt is open seems like the more robust fix.

To achieve this, we
- call resetKeyBindings both when opening and when closing the
search/filter prompt
- change the keybindings to only contain the ones for the search prompt
when that context is active.

Fixes #3875.
2024-09-02 18:34:28 +02:00
Stefan Haller
9ec77bba91 Don't allow opening a menu while the search or filter prompt is open
This solves several problems that arise from opening a menu while the prompt is
open. We might try to solve these in a different way, e.g. by dismissing the
search prompt before opening a menu, but restricting what you can do while the
prompt is open seems like the more robust fix.

To achieve this, we
- call resetKeyBindings both when opening and when closing the search/filter
  prompt
- change the keybindings to only contain the ones for the search prompt when
  that context is active.
2024-09-02 18:31:30 +02:00
Stefan Haller
4ec9262ff6 Ask to auto-stage unstaged files when continuing a rebase after resolving conflicts (#3879)
- **PR Description**

When lazygit sees that all conflicts were resolved, it auto-stages all
previously conflicted files and asks to continue the rebase. (There is
[a PR](https://github.com/jesseduffield/lazygit/pull/3870) open to make
this optional.)

It is a common situation for this popup to be opened in the background,
while the user is still busy fixing build errors in their editor. In
this case, coming back to lazygit and confirming the continue prompt
would result in an error because not all files are staged.

Improve this by opening another popup in this case, asking to stage the
newly modified files too and continue.

See
https://github.com/jesseduffield/lazygit/issues/3111#issuecomment-1801751982
and the following discussion further down in that issue.
2024-09-02 18:27:08 +02:00
Stefan Haller
ba21d4e651 Ask to auto-stage unstaged files when continuing a rebase after resolving conflicts 2024-09-02 18:24:36 +02:00
Stefan Haller
3cffed9412 Make auto-staging resolved conflicts optional (#3870)
- **PR Description**

Add user config `git.autoStageResolvedConflicts` (default true). When
set to false, users need to stage their conflicted files manually after
resolving conflicts, and also continue a merge/rebase manually when all
conflicted files are resolved.

Fixes #3111.
2024-09-02 18:20:20 +02:00
Stefan Haller
90b8fd242d Add config git.autoStageResolvedConflicts 2024-09-02 18:12:47 +02:00
Stefan Haller
1191aca60f Actually look for conflict markers in GetHasInlineMergeConflicts
So far, lazygit has always auto-staged files as soon as the conflict markers
disappeared from them, which means that we could rely on any file that still had
a status of "UU" to still contain conflict markers.

We are going to make the auto-staging optional in the next commit, and in that
case the user will want to manually stage "UU" files; so we must now check
whether the file contains conflict markers, and disallow the staging in that
case.
2024-09-02 18:12:47 +02:00
Stefan Haller
2f01af49e8 Non-sticky range selection diff (#3869)
- **PR Description**

When selecting a range of commits, show the combined diff for them.

Along the way, fix a few minor issues with the current implementation of
diffing mode; see the individual commit messages for details.

Fixes #3862.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc
2024-08-31 08:16:32 +02:00
Stefan Haller
32fef9aadb Add a simple integration test for non-sticky range diff 2024-08-28 19:51:15 +02:00
Stefan Haller
717cb40f05 Cleanup: remove now unused ListControllerTrait from SwitchToDiffFilesController 2024-08-28 19:51:15 +02:00
Stefan Haller
ef7d1a8602 Use non-sticky range diff when entering commit files panel
We make the name of the GetSelectedRefRangeForDiffFiles very specific on purpose
to make it clear that this is only for switching to diff files, so the
implementations can make assumptions about that (unlike GetSelectedRef, which is
used for different purposes and needs to stay more generic).
2024-08-28 19:51:15 +02:00
Stefan Haller
a6656e307c Extract a method CommitFilesContext.ReInit
Right now it doesn't do very much yet, but it's still worth it even in this
state, I'd say. The function is going to become a bit longer in the next commit,
though.
2024-08-28 19:51:15 +02:00
Stefan Haller
442592a149 Show diff for range selection in commits and sub-commits panel
In other views that show lists of commits (reflog and stash) it doesn't make
sense to show a range diff of selected entries because they don't form a linear
sequence, so we keep the previous behavior of showing the diff for the free end
of the selection range in those view.

The same applies to the commits view if the selection range includes rebasing
todos; these can have an arbitrary order, and a range diff doesn't make sense
for those.
2024-08-28 19:35:23 +02:00
Stefan Haller
ac335907ae Add ShortRefName to Ref interface 2024-08-28 18:27:52 +02:00
Stefan Haller
b07ce19b9a Add --stat -p to diff args in diffing mode
This is consistent with what we do for showing single commits (with git show),
and I find it very useful.
2024-08-28 18:27:52 +02:00
Stefan Haller
079c5a9905 Add prefix to main view diff when in diffing mode
Hopefully this will help alleviate the problem that diffing mode is sticky, and
you often forget that it's still on.

Make it magenta like the mode text in the information view.
2024-08-28 18:27:52 +02:00
Stefan Haller
a2c4fad410 Bugfix: properly set title of subcommits panel when refreshing
This fixes two problems:
- Set the title ref to the commit description (like
  SwitchToDiffFilesController.enter does), rather than just the hash
- SetTitleRef only sets the title of the DynamicTitleBuilder, but doesn't set it
  on the view; this only happens in ContextMgr.Activate, so you'd have to switch
  to a different side panel and then back to see the new title.
2024-08-28 18:27:52 +02:00
Stefan Haller
567e898e22 Bugfix: don't allow dropping patches from a custom patch that was made in diffing mode
The three nested `if` statements may looks strange, and you might wonder why we
don't have single one with &&. The answer is that later in this branch we will
add an `else` block to the middle one.
2024-08-28 18:27:52 +02:00
Stefan Haller
14a29d6d6f Bugfix: more comprehensive check whether custom patch must be reset
We need to compare more than just the "To" ref. The NewPatchRequired function
existed already for this purpose, it just wasn't used.
2024-08-28 18:27:52 +02:00
Stefan Haller
8e2ed8c538 Extract helper function currentFromToReverseForPatchBuilding
In the next commit it will be reused for checking whether we need to reset the
patch; and extracting it makes it easier to extend it for non-sticky diff ranges
later in the branch.
2024-08-28 18:27:52 +02:00
Stefan Haller
6ad4ffea3b Cleanup: remove unnecessary viewFiles indirection
viewFiles is only called from enter; it doesn't make much sense to fill in a
SwitchToCommitFilesContextOpts struct to pass it to viewFiles for this one call.
Simply inline viewFiles into enter and get rid of all that.
2024-08-28 18:27:52 +02:00
Stefan Haller
770d51634c Cleanup: remove diffFilesContext field of SwitchToDiffFilesController
I found this indirection confusing when reading the code. It looks like
SwitchToDiffFilesController is instantiated with different such contexts, but
it's always Contexts.CommitFiles, so just use that directly.
2024-08-28 18:27:52 +02:00
Stefan Haller
c51e13941c Cleanup: remove unused translated text 2024-08-28 16:54:38 +02:00
Stefan Haller
05ae0800c3 Add codespell support (config, workflow to detect/not fix) and make it fix few typos (#3751)
More about codespell: https://github.com/codespell-project/codespell .

I personally introduced it to dozens if not hundreds of projects already
and so far only positive feedback.

CI workflow has 'permissions' set only to 'read' so also should be safe.
2024-08-27 18:05:45 +02:00
Yaroslav Halchenko
4bbfe7b3cc [DATALAD RUNCMD] run codespell throughout fixing typos automagically
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^

Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
00530477c9 [DATALAD RUNCMD] Do interactive fixing of some ambigous typos
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w -i 3 -C 2 ./pkg/commands/oscommands/cmd_obj_runner.go ./pkg/integration/tests/branch/rebase_and_drop.go",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^

Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
90c1334535 Skip also for \nd
Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
83ef031922 [DATALAD RUNCMD] Do interactive fixing of some ambigous typos
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w -i 3 -C 2",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^

Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
820c2bc0fd custom skips for codespell
Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
a484954d74 Add rudimentary codespell config
Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
56be1a4950 Add github action to codespell master on push and PRs
Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Yaroslav Halchenko
1e8eb72b2f Do not git ignore .codespellrc
Signed-off-by: Yaroslav Halchenko <debian@onerussian.com>
2024-08-27 18:03:00 +02:00
Stefan Haller
18935bf7f0 Fix linter warnings (#3854)
- **PR Description**

Fix some linter warnings that I keep getting locally because I'm running
a newer version of golangci-lint than the pinned version we use on CI.

Also, update the pinned version in CI to 1.60 so that we are in sync
again.

Finally, upgrade the golangci-lint-action version to the latest,
although I'm not sure what difference this makes. The linting step runs
faster now, maybe because of better caching -- I noticed that
previously, loading and saving the cache took a very long time, which
often made the lint step the slowest of all.
2024-08-27 13:12:40 +02:00
Stefan Haller
457c4c248d Upgrade golangci-lint-action to latest version 2024-08-27 10:33:06 +02:00
Stefan Haller
8c553dcde9 Upgrade golang-ci to 1.60 2024-08-27 10:33:06 +02:00
Stefan Haller
a709caf138 Remove error return value from functions that always return nil 2024-08-27 10:33:06 +02:00
Stefan Haller
8dea2dab88 Ignore return values of fmt.Scanln 2024-08-27 10:33:06 +02:00
Stefan Haller
63aa32c521 Remove "double" formatting 2024-08-27 10:33:06 +02:00
Stefan Haller
24841f22f1 Use print instead of printf when there are no arguments 2024-08-27 10:33:06 +02:00
Stefan Haller
d712c2f199 Use format arguments instead of concatenating strings
That's what they are for.
2024-08-27 10:33:06 +02:00
Stefan Haller
4525216d26 Fix cancelled autostash resulting in stuck inline status (#3860)
- **PR Description**

When switching branches, there is a "Checking out" inline status
displayed next to the branch (but only sometimes? I think if the action
completes too quickly there is no status). If it does get displayed and
the checkout results in an autostash confirmation prompt, pressing
escape to cancel the action will cancel the checkout and close the
prompt. However, the inline status will still be displayed next to the
branch and doesn't go away by itself. Performing a manual UI refresh
(`R`) fixes the state.

If the prompt was confirmed instead, then this issue would not happen.

Reproduction:
```bash
git init
echo -e "a\n\nb" > file
git add .
git commit -m "add file"
echo -e "a\n\nc" > file
git add .
git commit -m "edit last line"
git checkout -b dev HEAD~
echo -e "b\n\nb" > file
lazygit
```

Switch to the other branch in the branches panel and press escape on the
prompt. The "Checking out" inline status should be stuck.
2024-08-27 10:30:31 +02:00
Brandon
ae61da7485 Fix cancelled autostash resulting in stuck inline status 2024-08-27 10:28:22 +02:00
Stefan Haller
fb9f6153fc Add missing closing quote in pager docs (#3864)
- **PR Description**

Add missing closing quote in pager docs.
2024-08-27 10:22:47 +02:00
Stefan Haller
a0c808842b Add missing closing quote 2024-08-27 10:16:53 +02:00
Stefan Haller
8a8490d97d Underline hyperlinks only on mouse hover (#3856)
- **PR Description**

Followup to #3825: we decided there that we don't want to underline
links in delta diffs by default, but only on mouse hover. This PR does
that; it makes it possible to decide per view whether links should be
underlined always, or only on hover. We set this to only on hover for
the main views, so that links in diffs are not underlined (also affects
the status view though), but all other links we want to underline always
for better discoverability.
2024-08-24 17:49:10 +02:00
Stefan Haller
68c7f9840a Set main views to underline hyperlinks only on mouse hover
Note that this doesn't only affect the diff views, which are the ones where we
want this, but also the status view, where the plan was to keep them underlined
always for better discoverability. We could make this configurable dynamically
(by adding another flag to ViewUpdateOpts), but actually I think it's fine this
way.
2024-08-24 17:45:54 +02:00
Stefan Haller
8d37f48744 Bump gocui 2024-08-24 17:45:51 +02:00
Stefan Haller
37f32755b5 Fix rendering regression introduced in #3839 (#3855)
- **PR Description**

Fix broken rendering introduced in #3839: the status view would often render only partially.
2024-08-24 11:51:53 +02:00
Stefan Haller
5380fe2483 Fix rendering regression introduced in #3839 2024-08-24 11:46:53 +02:00
Stefan Haller
8e71df3e53 Fix loading customCommands from per-repo config file (#3835)
- **PR Description**

Any newly loaded custom command coming from the per-repo config file should add
to the global ones (or override an existing one in the global one), rather than
replace all global ones.
2024-08-24 11:04:56 +02:00
Stefan Haller
30f43a245b Fix loading customCommands from per-repo config file
Any newly loaded custom command coming from the per-repo config file should add
to the global ones (or override an existing one in the global one), rather than
replace all global ones.

We can achieve this by simply prepending the newly loaded commands to the
existing ones. We don't have to take care of removing duplicate key assignments;
it is already possible to add two custom commands with the same key to the
global config file, the first one wins.
2024-08-24 11:01:25 +02:00
Stefan Haller
283ed29f10 Add a test that shows how per-repo config file replaces customCommands
We want to add to the global customCommands instead of replacing them.
2024-08-24 11:01:25 +02:00
Stefan Haller
ccd39bb8ae Fix wrong test assertion text
If a `t.FileSystem().FileContent("file.txt", Equals("bla"))` assertion fails
because the file doesn't exist, the error would say

   Expected path 'file.txt' to not exist, but it does

which is very confusing.
2024-08-24 11:01:25 +02:00
Stefan Haller
db40653202 Allow using </> and ,/. in sticky range select mode in patch explorer (#3837)
- **PR Description**

Don't cancel sticky range select when pressing `<`/`>`, `,`/`.` in the
patch explorer view. This was already working correctly in list views.

Fixes #3823.
2024-08-24 10:59:48 +02:00
Stefan Haller
d3940729eb Allow using </> and ,/. in sticky range select mode in patch explorer
They still cancel hunk selection mode, setting it to line selection mode, but if
range selection mode is on, we keep it on.
2024-08-24 10:56:20 +02:00
Stefan Haller
56a6ee6afb Cleanup: move SetLineSelectMode into AdjustSelectedLineIdx 2024-08-24 10:56:20 +02:00
Stefan Haller
a37a3fc4a1 Fix crash when filtering commits (#3838)
- **PR Description**

First we fix the crash reported in #3812 (see there for reproduction
recipe), and then we add a more general fix for avoiding crashes in
similar situations that we don't know about yet.

I'm not really happy with the brittleness of all this (the
interdependency between rendering and updating search results, that is),
but I haven't found a good way to untangle this yet.

Fixes #3812.
2024-08-24 10:55:12 +02:00
Stefan Haller
af87cd1dd6 Don't return model search results for commits when we don't have columnPositions
We fixed one specific scenario where this happened ealier in this branch, but in
case there are more that we don't know about yet, at least make sure we don't
crash.
2024-08-24 10:51:25 +02:00
Stefan Haller
e675025411 Return nil columnPositions when not rendering anything
... instead of returning a slice with a single [0] element. This makes it easier
to check whether we have columnPositions.
2024-08-24 10:51:25 +02:00
Stefan Haller
c3d5798c6c Fix early exit condition
I don't know what this condition is supposed to guard against, or whether we
really need it (it was added in 06ca71e955, and the commit message of that
commit only says "fix bug"). But if we do need it, then it seems that `>=` is
more correct than `>`.
2024-08-24 10:51:25 +02:00
Stefan Haller
15d17e16dd Call ReApplySearch after layout
This fixes a possible crash when exiting filter mode in the commits panel.
2024-08-24 10:51:25 +02:00
Stefan Haller
926061557b Make searching available in the filtered commits list
It is already possible to search a filtered list by searching first, and then
enabling a filter, so I found it inconsistent to not allow searching when you
are already filtering. One reason for not allowing this might be that the search
status (on the left) hides the filter status (on the right), but if we think
that's enough reason to not allow both at the same time, then we should cancel a
search when we enter filtering.
2024-08-24 10:51:25 +02:00
Stefan Haller
8522337f32 Scroll views up if needed to show all their content (#3839)
- **PR Description**

There are many situations where this can arise. Some examples are:
- the terminal window is small, and you are showing a view that shows more
content than fits into the view port, and the view is scrolled all the way
down; now you resize the terminal window to a taller size. Previously, the
scroll position of the view would stay the same, so it would add blank space
at the bottom; now it will scroll to fill that blank space with content
- expandFocusedSidePanel is on, you go to the bottom of a list view, now switch
to a different panel, then scroll that (now unfocused) panel all the way down
with the scroll wheel; now you focus that panel again. It becomes larger
because of the accordion behavior, but would show blank space at the
bottom.

And probably others that I can't remember right now. I only remember that I
always found it confusing to look at a view that had blank space at the bottom
even though it had more content to scroll into view.
2024-08-24 10:50:50 +02:00
Stefan Haller
6114f69ee5 Scroll views up if needed to show all their content
There are many situations where this can arise. Some examples are:
- the terminal window is small, and you are showing a view that shows more
  content than fits into the view port, and the view is scrolled all the way
  down; now you resize the terminal window to a taller size. Previously, the
  scroll position of the view would stay the same, so it would add blank space
  at the bottom; now it will scroll to fill that blank space with content
- expandFocusedSidePanel is on, you go to the bottom of a list view, now switch
  to a different panel, then scroll that (now unfocused) panel all the way down
  with the scroll wheel; now you focus that panel again. It becomes larger
  because of the accordion behavior, but would show blank space at the bottom.

And probably others that I can't remember right now. I only remember that I
always found it confusing to look at a view that had blank space at the bottom
even though it had more content to scroll into view.
2024-08-24 10:47:27 +02:00
Stefan Haller
0aa351443f Bump gocui 2024-08-24 10:47:25 +02:00
Stefan Haller
c28ecabfd8 Support hyperlinks from pagers (#3825)
- **PR Description**

Allows to use `delta --hyperlinks` as a pager, which turns line numbers
in the diff into clickable links that take you to the respective file.
For VS Code users, I recommend to combine this with
`--hyperlinks-file-link-format="vscode://file/{path}:{line}"`
so that it jumps to the right line.

In addition, I added a few commits that replaces our old, manual ad-hoc
handling of links in various places (status view, confirmation panels,
information view) with the new hyperlinks feature, which cleans up the
code a bit.

Fixes #3817.
2024-08-24 10:39:41 +02:00
Stefan Haller
bbd779b437 Use our new hyperlink support in the information view 2024-08-24 10:36:01 +02:00
Stefan Haller
b411897a5a Fix Decolorise to also strip hyperlinks
This is needed so that the information view is correctly aligned when we add
hyperlinks to it.
2024-08-24 10:36:01 +02:00
Stefan Haller
fb97c30080 Remove now unused function handleGenericClick 2024-08-24 10:36:01 +02:00
Stefan Haller
61b59837bb Use our new hyperlink support in confirmations 2024-08-24 10:36:01 +02:00
Stefan Haller
e65c0a9d5e Use our new hyperlink support in the status panel 2024-08-24 10:36:01 +02:00
Stefan Haller
3f7674a2e9 Add function to render a hyperlink
It might seem cleaner to integrate this into the text style system, so that you
could say `ts := ts.Url("some link")` and then `ts.Sprint("my text")`. However,
this would require adding a new field to TextStyle, which I didn't want to do.
2024-08-24 10:36:01 +02:00
Stefan Haller
fb81fc6057 Add documentation about delta --hyperlinks 2024-08-24 10:36:01 +02:00
Stefan Haller
e1acb6a547 Set an openHyperlink function on gocui 2024-08-24 10:36:01 +02:00
Stefan Haller
250eb14de1 Bump gocui 2024-08-24 10:35:59 +02:00
Stefan Haller
61ae5e16ae Improve mouse support for commit message panel (#3836)
#### PR Description

* Fix some minor problems related to cursor movement in an auto-wrapped
  commit message
* Allow clicking in an editable view to set the cursor (most useful in
  longer commit descriptions)
* Allow switching between commit message and description by clicking
2024-08-24 10:29:44 +02:00
Stefan Haller
e1efbfc842 Make it possible to scroll the commit description with the mouse wheel
It is just unexpected and confusing when it isn't.

There's something weird about the cursor position when scrolling it out of view;
it will be shown clamped to the visible area of the view (as if it had moved in
the opposite direction than the scroll direction), but then when you type
something again, or just move the cursor with the arrow keys, the view will jump
back to where the cursor really was. This looks confusing, and it might be
reason enough not to allow scrolling the view at all.
2024-08-24 10:21:30 +02:00
Stefan Haller
7d486cabeb Allow switching between commit message and description by clicking
It is annoying to have to tab to the description first before you can set the
cursor there by clicking.
2024-08-24 10:21:30 +02:00
Stefan Haller
c2e953a09f Cleanup: use the right context for CommitDescriptionController.Context()
It doesn't seem to be used by anything, it looks like we only need to implement
the method so that the IController interface is satisfied. But still, it doesn't
hurt to be correct here, and might avoid confusion in the future when somebody
does try to use the method.
2024-08-24 10:21:30 +02:00
Stefan Haller
59450c7d12 Bump gocui 2024-08-24 10:21:25 +02:00
Jesse Duffield
ca9e006cca Fix range select -> stage failure when deleted file is already staged (#3631)
- **PR Description**

Fix range select -> stage failure when deleted file is already staged.

Fixes https://github.com/jesseduffield/lazygit/issues/3603

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-08-24 10:31:46 +10:00
Brandon
387bdb1b84 Don't stage already staged deleted items 2024-08-24 09:36:44 +10:00
Jesse Duffield
5fb98655b3 Improve fixup commits script (#3853)
This script is failing currently on
https://github.com/jesseduffield/lazygit/pull/3631 because that fork's
master branch is 300 commits behind our own, but the feature branch is
up to date.

The thing is, we don't actually need to involve the master branch. All
we care about is the feature branch's own commits, so this commit simply
fetches those commits and checks them.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-08-24 09:36:30 +10:00
Jesse Duffield
addfa2f961 Improve fixup commits script
This script is failing currently on
https://github.com/jesseduffield/lazygit/pull/3631 because that fork's
master branch is 300 commits behind our own, but the feature branch is
up to date.

The thing is, we don't actually need to involve the master branch. All
we care about is the feature branch's own commits, so this commit simply
fetches those commits and checks them.
2024-08-24 09:27:02 +10:00
Stefan Haller
7679b109cb Specifying branch name source from refs/heads for fast forwarding (#3807)
- **PR Description**
This fixes #2625
2024-08-18 10:45:42 +02:00
Neko Box Coder
6a418c65ca Specifying branch name source from refs/heads for fast forwarding 2024-08-18 10:42:57 +02:00
Stefan Haller
aa55995924 Per-repo config files (and reloading of edited config files) (#3787)
- **PR Description**

Support per-repo user config files. For now we only support
`.git/lazygit.yml`; in the future we would also like to support
`./.lazygit.yml`, but that one will need a trust prompt as it could be
versioned, which adds quite a bit of complexity, so we leave that for
later.

We do, however, support config files in parent directories (all the way
up to the root directory). This makes it possible to add a config file
that applies to multiple repos at once. Useful if you want to set
different options for all your work repos vs. all your open-source
repos, for instance.

In addition, we support re-loading edited config files. This makes it
much easier to experiment with config settings, especially the ones that
affect the layout or color scheme, because you see the effect
immediately without having to restart lazygit.
2024-08-18 10:28:33 +02:00
Stefan Haller
5431c269d3 Add checkbox to PR template to make sure UserConfig entries can be hot-reloaded 2024-08-18 10:24:53 +02:00
Stefan Haller
73696629d9 Add dev documentation about using UserConfig 2024-08-18 10:24:53 +02:00
Stefan Haller
38b1255119 Add information about per-repo config files to Config.md 2024-08-18 10:24:53 +02:00
Stefan Haller
57de11b709 Show a confirmation when changing a config that can't be auto-reloaded 2024-08-18 10:24:53 +02:00
Stefan Haller
ce50533689 Reload changed user config files on terminal focus 2024-08-18 10:24:53 +02:00
Stefan Haller
18ad975573 Make custom commands reload when switching repos
Since onNewRepo calls resetKeybindings, which reinitializes the keybindings for
custom commands, all we have to do for this is store a pointer to a config
instead of storing the customCommands, so we get the up-to-date ones every time.
2024-08-18 10:24:52 +02:00
Stefan Haller
fd8e480363 Re-determine existing main branches if mainBranches config changed 2024-08-18 10:24:52 +02:00
Stefan Haller
3d6d677453 Store Common instead of just the list of configured main branches in MainBranches
This will make it possible to change the configured main branches at runtime.
We'll support this in the next commit.
2024-08-18 10:24:52 +02:00
Stefan Haller
aef8e71b82 Make gui.commitLength hot-reloadable 2024-08-18 10:24:52 +02:00
Stefan Haller
5872779faa Make gui.statusPanelView config hot-reloadable
It still doesn't update the view immediately when reloading the config, only the
next time the status panel is focused. But at least it does it then; writing the
code to update the panel when reloading the config is probably not justifiable.
2024-08-18 10:24:52 +02:00
Stefan Haller
04d7907864 Move initialization of global gocui properties to onUserConfigLoaded 2024-08-18 10:24:52 +02:00
Stefan Haller
65a2eccfdb Set custom author and branch colors and nerd font version after loading user config 2024-08-18 10:24:52 +02:00
Stefan Haller
4a272afc67 Reinitialize gui.ShowExtrasWindow after loading user config 2024-08-18 10:24:52 +02:00
Stefan Haller
2499a6c8a3 Initialize translation set after reading user config
This allows having per-repo config files with different languages per repo. Now
granted, this is not an important use case that we need to support; however, the
goal is to eventually make all configs hot-reloadable (as opposed to loading
them only once at startup), so this is one step in that direction.
2024-08-18 10:24:52 +02:00
Stefan Haller
74ed1ac584 Support per-repo config files
For now we only support .git/lazygit.yml; in the future we would also like to
support ./.lazygit.yml, but that one will need a trust prompt as it could be
versioned, which adds quite a bit of complexity, so we leave that for later.

We do, however, support config files in parent directories (all the way up to
the root directory). This makes it possible to add a config file that applies to
multiple repos at once. Useful if you want to set different options for all your
work repos vs. all your open-source repos, for instance.
2024-08-18 10:24:52 +02:00
Stefan Haller
d6d48f2866 Make common.UserConfig an atomic.Pointer for safe concurrent access
Currently, userConfig is only read once at startup and then never changes. Later
in this branch, we will add the possibility to reload the user config; this can
happen either when switching repositories, or when the user has edited the
config file. In both cases, reloading happens on the main thread, but the user
config could be accessed concurrently from background threads, so we need to
make this safe.
2024-08-18 10:24:52 +02:00
Stefan Haller
f98b57aa5e Change direct access to Common.UserConfig to a getter
This will allow us to turn the field into an atomic.Value for safe concurrent
access.
2024-08-18 10:24:52 +02:00
Stefan Haller
f114321322 Save changed user config back to disk in integration tests
At the moment, the user config is only read once at startup, so there's no point
in writing it back to disk. However, later in this branch we will add code that
reloads the user config when switching repos, which does happen quite a bit in
integration tests; this would undo the changes that a test made in its
SetupConfig function, so write those changes to disk to prevent that from
happening.
2024-08-18 10:24:52 +02:00
Stefan Haller
940700dc56 Introduce ConfigFile struct
This makes it more explicit how to deal with the different types of config
files: a user-supplied config file (via the LG_CONFIG_FILE env var) is required
to exist, whereas the default config file will be created if it is missing.

We will later extend this with repo-specific config files, which will be skipped
if missing.
2024-08-18 10:24:52 +02:00
Stefan Haller
be0fa98d11 Split createAllViews
Split it so createAllViews instanciates the views, and sets those properties
that are independent of the user config, and configureViewProperties which sets
those things that do depend on the user config. For now we call the second right
after the first, but later we'll call configureViewProperties after reloading
the user config.
2024-08-18 10:24:52 +02:00
Stefan Haller
e71fc43952 Remove return value of Gui.setColorScheme
It always returns nil.
2024-08-18 10:24:52 +02:00
Stefan Haller
cd0f72d66a Remove pointless reloading of UserConfig
It was added in 043cb2ea44, and the commit message was "reload config whenever
returning to gui". I don't understand what this means; Run() is called exactly
once after startup, so it would just reload the config again for no reason.

We will add a real way of reloading the config whenever it has changed later in
this branch.
2024-08-18 10:24:52 +02:00
Stefan Haller
48bb3a9dce Make fields of AppConfig private
We are going to make a few changes to the fields in this branch, and we can make
them with more peace of mind when we can be sure they are not accessed from
outside this package.
2024-08-18 10:24:52 +02:00
Stefan Haller
55d8e801f1 Use getters for AppState and UserConfig instead of accessing the fields directly
This will allow us to make them private.
2024-08-18 10:24:52 +02:00
Stefan Haller
54765d2236 Cleanup: remove unused method AppConfig.ConfigFilename 2024-08-18 10:24:52 +02:00
Stefan Haller
dbf6716b9b Cleanup: remove unused field IsNewRepo 2024-08-18 10:24:52 +02:00
Stefan Haller
a19bb0bbfe Cleanup: remove unused field DeafultConfFiles
It was also embarrassingly misspelled, so it's good that it's gone. :-)
2024-08-18 10:24:52 +02:00
Stefan Haller
75a95865ff Use filepath instead of path for file path operations
In practice, using path seems to work too, since Windows seems to be capable of
dealing with a path like C:/x/y instead of C:\x\y; but it's cleaner to do this
properly.
2024-08-18 10:24:52 +02:00
Stefan Haller
07dd8a2b07 Bump gocui 2024-08-18 10:24:52 +02:00
Stefan Haller
8bcfa3660a Fix pressing escape after clicking in diff view (#3828)
- **PR Description**

When clicking in a single-file diff view to enter staging (or custom
patch editing, when coming from the commit files panel), you needed to
press escape twice to exit, where the first press would seemingly do
nothing.
2024-08-17 11:34:10 +02:00
Stefan Haller
0e4d266a52 Fix pressing escape after clicking in diff view
When clicking in a single-file diff view to enter staging (or custom patch
editing, when coming from the commit files panel), you needed to press escape
twice to exit, where the first press would seemingly do nothing.

The reason for this was that after clicking in the diff we end up in non-sticky
range select mode, but only with a single line selected, which is basically
indistinguishable from line select mode.
2024-08-17 11:30:38 +02:00
Stefan Haller
7676572358 Improve template placeholders for custom commands (#3809)
- **PR Description**

Improve the template placeholders that are available for custom
commands:
- `SelectedCommit` replaces `SelectedLocalCommit`,
`SelectedReflogCommit`, and `SelectedSubCommit`
- `SelectedPath` is set to `SelectedCommitFilePath` when the CommitFiles
context is active

It still slightly bothers me that we don't make a similar unification
for `SelectedLocalBranch` and `SelectedRemoteBranch` (and others), but
it would be a bigger change to do that, and we decided in #3663 not to.

Fixes #3663.
2024-08-17 11:29:49 +02:00
Stefan Haller
7fb758cc1d Set SelectedPath to SelectedCommitFilePath in CommitFiles context 2024-08-17 11:26:31 +02:00
Stefan Haller
22f0d9cdd3 Expose SelectedCommit to custom commands, deprecate Selected{Local,Reflog,Sub}Commit
SelectedCommit is context-dependent and points to SelectedLocalCommit,
SelectedReflogCommit, or SelectedSubCommit depending on which panel is active.

If none of these panels is active, it returns the selected local commit, which
is probably the most useful default (e.g. when defining custom commands for the
Files panel).
2024-08-17 11:26:31 +02:00
Stefan Haller
1cb29cea15 Some cleanups for APIs related to contexts (#3808)
- **PR Description**

Some cleanups for APIs related to contexts. Most of these were triggered
by a TODO comment in the code.
2024-08-17 11:24:15 +02:00
Stefan Haller
1eb5d89f1d Remove bool return value of GetParentContext()
The comments that I'm deleting here explain why we need the bool; however, in
our case that's a theoretical issue. It would only arise if we ever were to pass
a nil context to SetParentContext, which we never do.
2024-08-17 11:14:51 +02:00
Stefan Haller
d570552206 Replace ActivateContext() with Context().Activate() 2024-08-17 11:14:51 +02:00
Stefan Haller
41f41ee4ee Rename ActivateContext/deactivateContext to Activate/deactivate
"Context" is redundant in the method names here.
2024-08-17 11:14:51 +02:00
Stefan Haller
94d6f4dae7 Replace IsCurrentContext() with Context().IsCurrent() 2024-08-17 11:14:51 +02:00
Stefan Haller
f30387e7f5 Replace CurrentPopupContexts() with Context().CurrentPopup() 2024-08-17 11:14:51 +02:00
Stefan Haller
3a8b97841f Rename PopupContexts() to CurrentPopup()
... for consistency with CurrentSide().
2024-08-17 11:14:51 +02:00
Stefan Haller
df3afb1b89 Replace CurrentSideContext() with Context().CurrentSide() 2024-08-17 11:14:51 +02:00
Stefan Haller
7f935c1ea8 Replace CurrentStaticContext() with Context().CurrentStatic() 2024-08-17 11:14:51 +02:00
Stefan Haller
7ed94c0410 Replace CurrentContext() with Context().Current() 2024-08-17 11:14:51 +02:00
Stefan Haller
8e15451117 Remove unused method RemoveContexts() 2024-08-17 11:14:51 +02:00
Stefan Haller
111d10fe5c Replace ReplaceContext() with Context().Replace() 2024-08-17 11:14:50 +02:00
Stefan Haller
98335361fd Replace PopContext() with Context().Pop() 2024-08-17 11:14:50 +02:00
Stefan Haller
bd36b8a95e Replace PushContext() with Context().Push() 2024-08-17 11:14:50 +02:00
Stefan Haller
d89dc967b8 Rename "Custom Command" to "Shell Command" (#3800)
- **PR Description**

The double use of the term "Custom Command" for both shell commands and
user-configured keybindings was confusing.
2024-08-17 10:59:23 +02:00
Stefan Haller
dbca9306de Rename "Custom Command" to "Shell Command"
The double use of the term "Custom Command" for both shell commands and
user-configured keybindings was confusing.
2024-08-17 10:56:03 +02:00
Stefan Haller
0cbe08b105 Add new integration tests folder "shell_commands"
The folder custom_commands contained tests for both custom commands (the ones
you configure in config.yml) and shell commands (the ones you execute at the ":"
prompt). I always found this confusing, so separate these into two different
folders.
2024-08-17 10:56:03 +02:00
Stefan Haller
af5b19a9da Fix line coloring when using the delta pager (#3820)
- **PR Description**

The green/red bars for added/deleted lines in delta wouldn't extend to
the right edge of the view, but end after the last printable character.
This was broken before, and fixed in #1386 two years ago, but then it
broke again in v0.42 because of #3687.
2024-08-17 10:53:47 +02:00
Stefan Haller
da8e4e44b7 Bump gocui 2024-08-17 10:50:32 +02:00
Stefan Haller
69666d1089 Switch tabs with panel jump keys (#3794)
- **PR Description**

When using the panel jump keybindings (`1` through `5` by default), and
the target panel is already the active one, go to the next tab instead.
2024-08-17 10:39:57 +02:00
Stefan Haller
b37d6dcd1c When using the panel jump keys and the target panel is already active, switch tabs 2024-08-17 10:37:00 +02:00
Stefan Haller
c72be6cbf3 Allow using shell aliases in interactive custom commands (#3793)
- **PR Description**

When executing an interactive custom command, use the user's shell
rather than "bash", and pass the -i flag. This makes it possible to use
shell aliases or shell functions which are not available in
non-interactive shells.

In previous attempts to solve this, concerns were brought up: [this
one](https://github.com/jesseduffield/lazygit/pull/2096#issuecomment-1257072541)
is addressed by using the interactive shell only for custom commands but
not anything else. [This
one](https://github.com/jesseduffield/lazygit/pull/2096#issuecomment-1343341795)
is a little dubious and unconfirmed, so I'm not very worried about it.

Supersedes #2096 and #3299. Fixes #770, #899, and #1642.
2024-08-17 10:34:40 +02:00
Stefan Haller
5a3049485c Use an interactive shell for running custom commands
Also, use the user's shell (from the SHELL env variable) instead of bash. Both
of these together allow users to use their shell aliases or shell functions in
the interactive command prompt.
2024-08-17 10:32:18 +02:00
Stefan Haller
39e77d1823 Extract helper function quotedCommandString
Will be reused in the next commit.
2024-08-17 10:32:18 +02:00
Stefan Haller
da94ee7a9a Fix redraw bug (stale content) in commits view (#3783)
- **PR Description**

When switching from a branch with fewer commits than fit in the commits
panel to another branch with even fewer commits, the last few commits of
the old branch were still drawn at the bottom.

Fixes #3778.
2024-08-17 10:29:39 +02:00
Stefan Haller
62ca873ddd Bump gocui 2024-08-17 10:25:16 +02:00
Stefan Haller
9404c2309c Allow GPG reword for last commit (#3815)
- **PR Description**
This PR fixes #3806, which is only for the last commit.
Would be good if this could be extended to commits older than head.
2024-08-16 13:11:17 +02:00
Neko Box Coder
4a2508e960 Allow rewording for last commit using GPG 2024-08-16 13:08:31 +02:00
Neko Box Coder
ce6388bdfa Adding guard to not do reword under git_commands when using gpg 2024-08-15 08:54:23 +02:00
Stefan Haller
58d7467180 Fix lack of icon assignation when extension don't match capitalization (lowercase) (#3810)
- **PR Description**
The extension icon map contain all extensions on lowercase, when a file
don't have extension on lowercase the string don't match and icon is not
assigned.
2024-08-09 12:19:46 +02:00
hasecilu
cb53e377a8 Fix lack of icon assignation when extension don't match capitalization 2024-08-08 15:18:02 -06:00
Stefan Haller
a3560eb451 Don't exit app when GetRepoPaths call fails during startup (#3779)
- **PR Description**
Fixes #3740 

As explained in the issue, 7a67096 moved some code around that caused a
call to `GetRepoPaths` to occur before `setupApp`, which usually handles
the scenario where we are not in a git directory. `GetRepoPaths` returns
an error if the path isn't a git repository, which caused the app to
exit before we reached `setupApp`.

When starting up lazygit, we ignore (and log) the error returned by
`GetRepoPaths`, and continue instead of exiting early. This allows us to
reach the step where we follow the user's `notARepository` config entry.
2024-08-03 18:37:53 +02:00
ppoum
ef4fd70f9c Ignore GetRepoPaths error when launching 2024-08-03 10:02:47 -04:00
Stefan Haller
74fe069da9 feat(custom command): support multiple contexts within one command (#3784)
- **PR Description**

For some custom commands, they can be used in multiple contexts. But for
now, if we want to do this, we should copy and paste the same config
times and times with just a different **context**.

Related issue: #3759 

This PR makes it possible to use multiple contexts in the `context` field of 
`customCommand`, separated by comma.
2024-08-02 11:59:39 +02:00
Yam Liu
542030f190 Support multiple contexts within one command, add tests, update doc 2024-08-02 11:55:29 +02:00
Yam Liu
206b2c6f0b Add a unit test case for global context 2024-08-02 11:55:29 +02:00
Stefan Haller
dc87592876 Add a readme file for the JSON files in pkg/i18n/translations (#3781) 2024-07-26 11:04:18 +02:00
Stefan Haller
37f35da436 Add a readme file for the JSON files in pkg/i18n/translations
People have started sending PRs that change these files.
2024-07-26 11:00:10 +02:00
Stefan Haller
f598da0df2 Reapply "Check for fixup commits on CI" (#3745)
Re-enable the check for fixup commits (see #3742), make it work for
forks, and extend it to "amend!" and "WIP" commits (and a few others).
2024-07-13 15:17:50 +02:00
Stefan Haller
20ccb03a45 Extend check for fixups
Also check for squash! and amend! (these are all anchored to the beginning of
the subject), and WIP and DROPME for good measure (but only if they occur in the
first line, otherwise it wouldn't let me merge this very commit :)
2024-07-13 15:15:01 +02:00
Stefan Haller
891362dfb2 Use extended regex rather than perl regex in the git call
My local git is not compiled with PCRE support, so using -E makes it easier for
me to test the script locally. And -E is good enough for the simple matching we
want to do here.
2024-07-13 15:02:34 +02:00
Stefan Haller
463cf35e64 Make checkout action work with forks 2024-07-13 14:39:28 +02:00
Stefan Haller
1919a2d2d6 Reapply "Check for fixup commits on CI"
This reverts commit f2db9fa3f9.
2024-07-13 14:08:44 +02:00
Stefan Haller
71ad3fac63 Fix language auto detection (#3744)
- **PR Description**

Fix a regression (introduced with #3649) that broke language
auto-detection. When starting lazygit with the `gui.language` config set
to "auto" (which is the default), lazygit would fail to start if the
LANG environment is set to one of our supported languages.

For example:
```
$ export LANG=nl_NL
$ lazygit
2024/07/13 11:43:03 open translations/nl-NL.json: file does not exist
```

Fixes #3743
2024-07-13 12:14:39 +02:00
Stefan Haller
ae4a579153 Fix language auto-detection
Starting lazygit with an environment containing LANG=ko_KO or LANG=nl_NL would
result in an error at startup.
2024-07-13 12:07:59 +02:00
Stefan Haller
da86096e19 Add test that demonstrates bug with language auto-detection 2024-07-13 12:07:59 +02:00
Jesse Duffield
e1d973d62a README.md: Update Sponsors (#3732)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-07-13 15:04:32 +10:00
github-actions[bot]
0489b11c0c README.md: Update Sponsors 2024-07-13 05:03:33 +00:00
Jesse Duffield
c7a9b9ca07 Add support for setting the similarity threshold for detecting renames (closes #2904) (#3025)
- **PR Description**
Implement the feature as discussed in #2904.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go run scripts/cheatsheet/main.go
generate`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

---

_Edit: Previously I have left the "Text is internationalised" checkbox
empty, as I thought that it would also have to include translations, but
as I understand currently, that would be "localization" instead, so I
ticked it._

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-13 15:03:21 +10:00
Jesse Duffield
f2db9fa3f9 Revert "Check for fixup commits on CI"
This reverts commit 7652d579f5.

Not working on forks, and I don't have time to fix right now
2024-07-13 14:54:20 +10:00
István Donkó
b9107d5fc8 Support setting the similarity threshold for detecting renames 2024-07-13 14:24:26 +10:00
Jesse Duffield
bfe2dd4ed8 Check for fixup commits on CI (#3742)
I keep merging PRs that still have fixup commits on them! This will make
it impossible to do so

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-13 13:51:10 +10:00
Jesse Duffield
7652d579f5 Check for fixup commits on CI
I keep merging PRs that still have fixup commits on them! This will make
it impossible to do so
2024-07-13 13:41:47 +10:00
Jesse Duffield
73bcbe4ee2 Extend icon coverage on remotes and file extensions (#3484)
- **PR Description**

Initially I opened #3426 issue, this PR is targeted to fix that.

- **Please check if the PR fulfills these requirements**

* [X] Cheatsheets are up-to-date (run `go generate ./...`)
* [X] 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)
* [X] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [X] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [X] You've read through your own file changes for silly mistakes etc

This is the result from the remote icons that I posted on the issue.
Note: The FreeBSD only is triggered if the remote is "git.FreeBSD.org",
note the capitalization

Edit: btw, there are also icons for gitea -> `nf-linux-gitea`, \uf339, 
and forgejo -> `nf-linux-forgejo`, \uf335,  if someone is interested on
some instances that use that sofware.


![image](https://github.com/jesseduffield/lazygit/assets/53124818/d68aa9a1-5a3d-446a-af38-650754056f06)

Would be nice if in the future the user can make overrides via config
file.
```yml
icon_overrides:
  filenames:
    Cargo.toml: 🦀
    Cargo.lock: 🦀
  extensions:
    rs: 🦀
    nix: ❄
```

Fix #3426

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-13 13:32:26 +10:00
hasecilu
cd01e4e7c2 fixup! Add icons for some file names 2024-07-13 13:23:12 +10:00
hasecilu
c5de9cfd8e fixup! Add icons for some file extensions 2024-07-13 13:23:12 +10:00
hasecilu
1129e0e4a0 Add icons for some git remotes 2024-07-13 13:23:12 +10:00
hasecilu
981f1fa7aa Add icons for some file extensions 2024-07-13 13:23:12 +10:00
hasecilu
cad4581d05 Add icons for some file names 2024-07-13 13:23:12 +10:00
hasecilu
f0af42270e Update link from unmaintained exa to maintained eza 2024-07-13 13:23:12 +10:00
Stefan Haller
e0377f2bce Only add commit prefix if branch name matches regex pattern (#3703)
- **PR Description**
Currently if a branch name does not match a regex pattern defined in the
config.yaml (commitPrefix/es) the commit message box is populated with
the branch name as is - this does not match expectations. A prefix
should only be added if there is a match on the regex pattern.

This PR seeks to change that by checking for a match before calling
ReplaceAllString - see Issue #3695

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [-] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-07-10 09:13:25 +02:00
Luke Swan
968060a5ec Ensure branch name matches pattern before replace
Amend test for non-matching branch name
2024-07-10 09:05:41 +02:00
Luke Swan
07fe828f60 Add initial test for non-matching branch name 2024-07-10 09:05:33 +02:00
Jesse Duffield
b004b2e275 Change RepoPaths to be acquired via RepoPathCache (#3284)
### **PR Description**
In order to optimize the number of git calls made this change implements
a RepoPathCache as the API by which RepoPaths instances are acquired.
This primarily affects app startup and worktree enumeration.

This introduces a new dependency on
[go-memoize](https://github.com/kofalt/go-memoize), which is a
lightweight wrapper around go-cache and singleflight, in order to ensure
that the cache is concurrency safe. (As compared to a simple map, e.g.)
See the go-memoize README for details.

Fixes #3227.

### **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-07-07 15:43:15 +10:00
John Whitley
7a670964cd Optimize number of early calls to GetRepoPaths
This change reduces the number of calls during application startup to
one, calling GetRepoPaths() earlier than previously and plumbing the
repoPaths struct around to achieve this end.
2024-07-06 12:09:48 -07:00
Jesse Duffield
a138a31c72 README.md: Update Sponsors (#3580)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-07-06 23:00:22 +10:00
github-actions[bot]
31456a8caa README.md: Update Sponsors 2024-07-06 12:08:18 +00:00
Jesse Duffield
22764cd207 Switch between multiple log views (#3354)
- **PR Description**

* Fixes jesseduffield/lazygit#1363
* Allow switching between up two three log views

Seeing as the last activity related to this issue was over a year ago, I
decided to take a stab at this.
The implementation should be fully backwards compatible. Simply add
`allBranchesLogCmdAlt1` and/or `allBranchesLogCmdAlt2` to your config
file to use them when cycling between log commands using 'a'.
You can even use `allBranchesLogCmdAlt2` together with
`allBranchesLogCmd` (skipping `allBranchesLogCmdAlt1`) if you want, it
should not affect usability.

This is my first contribution to LazyGit, but I have experience with Go.

Changes:

- Introduced two new optional user config commands,
allBranchesLogCmdAlt1+2
- When pressing 'a' in the Status view, cycle between non-empty,
non-identical log commands
- There will always be at least one command to run, since
allBranhesLogCmd has a default

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 22:08:05 +10:00
Martin Kock
be21328c69 Allow cycling between multiple log commands
- Introduced a new optional user config command, allBranchesLogCmds
- When pressing 'a' in the Status view, cycle between non-empty, non-identical log commands
- There will always be at least one command to run, since allBranhesLogCmd has a default
- Update documentation & write an integration test
- Update translation string
2024-07-06 22:02:47 +10:00
Jesse Duffield
3d14893c65 Add Token credential request handling (#3647)
- **PR Description**

Asking for 2FA Token prompt when an additional authentication is
configured for git over SSH

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 21:47:40 +10:00
Aleksei Larkov
8813587961 Add Token credential request handling
Asking for 2FA Token prompt when an additional authentication is configured for git over SSH
2024-07-06 21:44:10 +10:00
Jesse Duffield
13bd4b964f Add flox install (#3656)
- **PR Description**

`lazygit` is available in Flox today, and seems to be working well.
Since Flox is related to Nix, I decided a good place would be right
below the Nix install section. 😉

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 21:35:19 +10:00
Bryan Honof
eae76a97e9 docs: Add flox install 2024-07-06 21:27:08 +10:00
Jesse Duffield
34214af41f Fix multi selection stage/discard not working for files with substrings (#3599)
- **PR Description**

I found an issue with multi selection stage/discard. Here is a minimal
repro:
```bash
git init
touch a
touch aa
lazygit
```

Select both files using shift and hit space. Only `a` is staged.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 21:26:32 +10:00
Brandon
38aa5b89ab Simplify integration test 2024-07-06 21:22:04 +10:00
Brandon
2e5b570bb6 Add integration test 2024-07-06 21:22:04 +10:00
Brandon
a5eec48b4b Fix multi selection stage/discard not working for files with substrings 2024-07-06 21:22:04 +10:00
Jesse Duffield
94cf2cc7df Bump actions/checkout, actions/setup-go, actions/cache/restore, actions/cache/save (#3594) 2024-07-06 21:21:32 +10:00
kyu08
ac30aee1b8 Bump actions/checkout, actions/setup-go, actions/cache/restore, actions/cache/save 2024-07-06 21:17:29 +10:00
Jesse Duffield
d3780fd57d Allow setting a default name when creating new branches (#3487)
- **PR Description**

I commonly prefix my branch names with my first initial and last name,
such as this one (`ecubit/branch-prefixes`). It can be a bit annoying to
type out.

This PR adds a config option to set a default value for the name in the
branch creation modal.

If there would have previously been a branch name autofilled (I do not
know all such cases), this change has no effect.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
- `CONTRIBUTING.md` says I may submit without doing localization (and I
am unable)
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-07-06 21:16:31 +10:00
Elliot Cubit
5959f7bc8e Allow setting a default name when creating new branches 2024-07-06 21:06:28 +10:00
Jesse Duffield
436240bbeb Add nerdfont icons for .bicep & .bicepparam files (#3053)
- **PR Description**
As the title says, I've added the v3 nerd font icons for
[Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep).

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 20:31:04 +10:00
Scott McKendry
2317dac730 fix formatting 2024-07-06 20:27:03 +10:00
Scott McKendry
08bd36ea78 Add bicep & bicepparam icons 2024-07-06 20:27:03 +10:00
Jesse Duffield
ab31991e13 Upgrade to Alpine Linux v3.19 (#3541)
- **PR Description**

Alpine v3.15 is out-of-date since 2023-11-01 and is not getting any
security updates anymore: https://alpinelinux.org/releases/

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-07-06 20:25:05 +10:00
fossdd
4df8f87715 Upgrade to Alpine Linux v3.19
Alpine v3.15 is out-of-date since 2023-11-01 and is not getting any security updates anymore: https://alpinelinux.org/releases/
2024-07-06 20:21:40 +10:00
Stefan Haller
62a018c1d4 Update tracking behaviour for branches created from remote branches (#3712)
### Overview

| Current Behaviour | New Behaviour |
|--|--|
| Local branches will **always** track the remote branches they were
created from. | Local branches will track the remote branches they were
created from **only if their names match**. |

### Description

The current behaviour when creating a new branch off of a remote branch
is to always track the branch it was created from.

For example, if a branch 'my_branch' is created off of the remote branch
'fix_crash_13', then 'my_branch' will be tracking the remote
'fix_crash_13' branch.
It is common practice to have both the local and remote branches named
the same when the local is tracking the remote one. Therefore, it is
reasonable to expect that 'my_branch' should not track the remote
'fix_crash_13' branch.

The new behaviour when creating a new branch off of a remote branch is
to track the branch it was created from only if the branch names match.
If the branch names DO NOT match then the newly created branch will not
track the remote branch it was created from.

For example, if a user creates a new branch 'fix_crash_13' off of the
remote branch 'fix_crash_13', then the local 'fix_crash_13' branch will
track the remote 'fix_crash_13' branch.
However, if the user creates a new branch called 'other_branch_name' off
of the remote branch 'fix_crash_13', then the local 'other_branch_name'
branch will NOT track the remote 'fix_crash_13' branch.


- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-07-04 22:37:31 +02:00
T.
b26ff43d9e Update tracking behaviour for branches created from remote branches
The current behaviour when creating a new branch off of a remote branch
is to always track the branch it was created from.

For example, if a branch 'my_branch' is created off of the remote branch
'fix_crash_13', then 'my_branch' will be tracking the remote
'fix_crash_13' branch.

It is common practice to have both the local and remote branches named
the same when the local is tracking the remote one. Therefore, it is
reasonable to expect that 'my_branch' should not track the remote
'fix_crash_13' branch.

The new behaviour when creating a new branch off of a remote branch is
to track the branch it was created from only if the branch names match.
If the branch names DO NOT match then the newly created branch will not
track the remote branch it was created from.

For example, if a user creates a new branch 'fix_crash_13' off of the
remote branch 'fix_crash_13', then the local 'fix_crash_13' branch will
track the remote 'fix_crash_13' branch.
However, if the user creates a new branch called 'other_branch_name' off
of the remote branch 'fix_crash_13', then the local 'other_branch_name'
branch will NOT track the remote 'fix_crash_13' branch.
2024-07-04 22:34:36 +02:00
Stefan Haller
a047fba9f7 Update translations from Crowdin (#3707)
Add a very simple script to semi-automate the process of updating the
non-English translation files from Crowdin.
2024-07-01 08:43:35 +02:00
Stefan Haller
974016cfba Update translations from Crowdin
No content changes yet, because nobody has edited anything in Crowdin so far.

However, this changes a few `\u003` to `<` (pretty sure that was an artefact of
how we manually generated the json files in #3649), and it removes all the
translations that are identical to the English version, which I guess is a good
thing (but doesn't make a difference in practice).
2024-07-01 08:40:13 +02:00
Stefan Haller
5b6dbe57b1 Add script to update translation files from Crowdin 2024-07-01 08:40:13 +02:00
Stefan Haller
92d4073b2a Remove unused TranslationSet entries
Found these by looking for empty strings in en.json.
2024-07-01 08:40:13 +02:00
Stefan Haller
c27a7e0816 Add missing english text
I was looking for empty strings in en.json, that's how I found this one. It
resulted in an empty log entry when adding a co-author to an existing commit.
2024-07-01 08:40:13 +02:00
Stefan Haller
f3c9443ec8 Fix go generate on windows (#3706)
Fix two problems with running `go generate ./...` on Windows:
- the command would error out with `panic: Default config starting
comment not found` (depending on the setup of the local git client)
- after running the command, all files would show up as modified in git,
but without a diff. Staging the files would make them disappear again,
except for those that actually had changes.

Fix both of these by configuring git to check out the generated text
files with Unix line endings.
2024-07-01 08:39:39 +02:00
Stefan Haller
71a62b7573 Re-add a vendor .gitattributes file
This was previously ignored by our top-level .gitignore file; now that we no
longer do that, running `go mod vendor` brings it back.
2024-07-01 08:36:57 +02:00
stk
61313e5dfa Add .gitattributes file
This tells git to checkout all .md and .json files with Unix line feeds,
even on Windows. This shouldn't be a problem for working with these
files on Windows, as all modern text editors and IDEs should be capable
of editing Unix files transparently; but it makes it possible to run
`go generate ./...` on Windows, which assumes Unix line feeds in a few
places.
2024-07-01 08:36:57 +02:00
stk
94a1c27916 Normalize line endings of docs/README.md
For some reason this was checked in with CRLF line endings; change it to
just LF, like all other text files.
2024-07-01 08:36:57 +02:00
Stefan Haller
6da4f9a787 Fix running lazygit with a language other than English on Windows (#3705)
On Windows, trying to use lazygit with a language other than English
would result in the error message `open translations\ja.json: file does
not exist`.
2024-07-01 08:36:38 +02:00
stk
398ceb1dd9 Fix loading translation set json files on Windows
It seems that the embed.FS always uses foreward slashes, even on
Windows.

This not only affected generating the cheatsheets, but also loading a
translation file in production.
2024-06-30 10:41:48 +02:00
Stefan Haller
6788825ed3 Make opening git difftool more consistent (#3691)
The default shortcut to open git difftool (`ctrl+t`) is not available on
the "Local Branches" window. It is available when selecting a commit
from a local branch, a remote branch, or a tag from the "Local Branches"
window.

This is inconsistent since branches or tags are also commits, the
shortcut should also work on them directly.

This commit remedies this inconsistency by allowing the use of the
shortcut directly on a branch or a tag. The shortcut works both in the
"standard" mode and the "diffing" mode.
2024-06-30 10:32:51 +02:00
T.
2335772db6 Make opening git difftool more consistent
The default shortcut to open git difftool (ctrl+t) is not available on
the "Local Branches" window. It is available when selecting a commit
from a local branch, a remote branch, or a tag from the "Local Branches"
window.

This is inconsistent since branches or tags are also commits, the
shortcut should also work on them directly.

This commit remedies this inconsistency by allowing the use of the
shortcut directly on a branch or a tag. The shortcut works both in the
"standard" mode and the "diffing" mode.
2024-06-30 10:27:28 +02:00
Jesse Duffield
1285554cb2 Add Squash merge (#3566)
- **PR Description**

Hello,

This PR add merge --squash. A PR already exist
https://github.com/jesseduffield/lazygit/pull/3130, but the author
abandoned it, so I remake it.
I modified to fit most of the comment made except this one
https://github.com/jesseduffield/lazygit/pull/3130/files#r1404808121. I
didn't find an existing example and thus didn't know to modify the code
to fit it to the new way of doing things.

There's still the choice box to commit or not to do as discussed
https://github.com/jesseduffield/lazygit/pull/3130#issuecomment-2112324990.
I'll do it when I have time, I first need to read the code to see how it
really works.

Also only english has been made for now. 


![image](https://github.com/jesseduffield/lazygit/assets/94681915/f648ca13-3d16-4703-a074-a83fe9a1eb0f)


- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-06-30 11:05:09 +10:00
Noah
232be05785 feat: squash merge 2024-06-30 11:01:03 +10:00
Stefan Haller
8990026358 Make commit author length configurable, take 2 (#3688)
- **PR Description**

This reverts #3625, and instead adds two new config keys
`commitAuthorShortLength` and `commitAuthorLongLength` for achieving the
same thing, but with more flexibility.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-29 11:31:52 +02:00
Stefan Haller
bd782f16dd Provide two config keys for configuring the author length in commits view
One is for the normal view, the other for the expanded view.
2024-06-29 11:28:44 +02:00
Stefan Haller
7be82d4713 Revert "Add user config gui.commitAuthorFormat (#3625)"
This reverts commit 3af545daf7, reversing
changes made to 629b7ba1b8.

We changed our mind about this and want to provide different options for
achieving the same thing, but with more flexibility.
2024-06-29 11:28:00 +02:00
Stefan Haller
5dbdbd8425 Turn off the highlight of the suggestions panel when it loses focus (#3696)
- **PR Description**

The highlight is normally turned off in HandleFocusLost, but that's not
called when using ReplaceContext (and changing this would be a lot of
work, it seems), so turn it off manually for now.

For a moment I considered whether we want to show the new inactive
highlight when switching from suggestions to the prompt (actually this
did happen on master), but I decided against it for several reasons:
- it's not quite the right concept (the suggestions view is not the
"parent" context of the prompt),
- there's no benefit from seeing one of the suggestions selected (and
the selection would change arbitrarily when changing the filter string)
- there would be visual problems when the suggestions become empty, in
which case we would still highlight the first empty row (which you can
only see if you set the gui.theme.inactiveViewSelectedLineBgColor config
to some color). Now this could be considered a bug in the focus
management of the suggestions panel, but it doesn't seem worth fixing
this; the problem goes away by turning off the highlight.
2024-06-29 11:27:26 +02:00
Stefan Haller
9b73b68f95 Turn off the highlight of the suggestions panel when it loses focus
The highlight is normally turned off in HandleFocusLost, but that's not called
when using ReplaceContext (and changing this would be a lot of work, it seems),
so turn it off manually here for now.
2024-06-29 11:24:08 +02:00
Stefan Haller
c3715d0f86 Extract helper function SuggestionsController.switchToConfirmation
This fixes the minor issue that the subtitle of the suggestions view wasn't
emptied when hitting "e" to edit a custom command.
2024-06-29 11:24:08 +02:00
Stefan Haller
696b8ba457 Always reapply filters on filtered views when model changes, even inactive ones (#3697)
- **PR Description**

A filtered view would show stale data when the model changes but the
view is inactive. I think this could only happen when changing some git
state outside of lazygit; for example, when creating a new branch while
the branches panel has a filter set, but doesn't have the focus. (See
the added test for an example.)
2024-06-29 11:23:38 +02:00
Stefan Haller
e205c6ba7f Always reapply filters on filtered views, even inactive ones 2024-06-28 08:23:27 +02:00
Stefan Haller
c6df856079 Add test demonstrating a problem with updating the filter when the model changes
We only update the filter when the filtered view has the focus.
2024-06-28 08:23:27 +02:00
Stefan Haller
26c3e0d333 Stagger popup panels (#3694)
- **PR Description**

Sometimes we open a popup panel on top of another one; an example is the
`<c-o>` menu in the commit message editor, or the "add co-author" prompt
that appears on top of the commit message panel. We just added a new one
in #3676, which is the confirmation that appears when pasting a commit
message over an existing one.

Currently, these panels are sized and positioned independently of each
other, which looks ugly and makes it hard to see what's going on:
<img width="720" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/1225667/6d84fc85-fadb-4f03-a973-868bc29d79f5">

Improve this by offsetting the new panel a bit down and to the right
from the one below it:
<img width="750" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/1225667/c0c39f88-356b-4add-b335-4db2e54496ed">

Along the way we clean up the code a bit and fix a few minor issues; see
the individual commit messages for details.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-28 08:17:36 +02:00
Stefan Haller
4b6479b25f Stagger popup panels
When opening a popup panel on top of another one, offset the new one a little
bit down and to the right.
2024-06-28 08:14:07 +02:00
Stefan Haller
1ab1fb3599 Resize all open popup panels in layout, not just the topmost one
Probably not the most import feature in the world, but when resizing the
terminal window while multiple popup panels were open at the same time, we would
only resize the topmost one.

The main reason for changing this is because it makes the next commit easier to
implement.
2024-06-28 08:14:07 +02:00
Stefan Haller
1d502d3245 Remove return value from ResizeCurrentPopupPanel
It always returned nil, so there's no point in returning an error.
2024-06-28 08:14:07 +02:00
Stefan Haller
bb01648521 Remove redundant calls to resize editable panels at creating time
The only purpose of this was to scroll the editable text correctly (see
https://github.com/jesseduffield/lazygit/pull/2146); now that gocui takes care
of that, we no longer need to do this.
2024-06-28 08:14:07 +02:00
Stefan Haller
32cfe7a5c3 Bump gocui 2024-06-28 08:14:05 +02:00
Stefan Haller
b795d91fa8 Remove redundant resizeConfirmationPanel() call at panel creating time
We resize the panel in layout, so there's no need to do that after creation.
2024-06-27 10:18:12 +02:00
Stefan Haller
ccc620e5fc Remove duplicate function
ResizeConfirmationPanel and resizeConfirmationPanel were identical, get rid of
one of them.
2024-06-27 10:14:00 +02:00
Stefan Haller
34d7afc0e9 Remove unused functions 2024-06-27 10:14:00 +02:00
Stefan Haller
22dc7fece9 Have only one of commit message and description on the context stack at a time
This is how we do it for confirmation with suggestions too, so be consistent. It
will make things easier later in this branch if we only have one context per
"panel" on the stack, even if the panel consists of two views.

Concretely this means:
- only push the message context onto the stack when opening the panel (this
  requires making the description view visible manually; we do the same for
  suggestions)
- when switching between message and description, use ReplaceContext rather than
  PushContext
2024-06-27 10:14:00 +02:00
Stefan Haller
c3d1a79a89 Fix clicking outside of the commit description panel or suggestions panel
We forgot to handle the "suggestions" and "commitDescription" view names.

Instead of listing all the names of views that can appear in popups though,
let's use the context kind for this, which feels more robust.

This is a change in behavior: previously, clicking outside of the search or
filter prompt would close the prompt, now it no longer does (because search has
a persistent popup kind, but it wasn't listed in the list of view names before).
2024-06-27 09:36:50 +02:00
Stefan Haller
63a523c2fc Add command to paste commit message from clipboard (#3676)
- **PR Description**

Resolves #3672

Added an entry to the commit message menu called "Paste commit message from clipboard",
which splits the clipboard into subject and description and pastes both into their respective fields.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-27 08:36:52 +02:00
WaterLemons2k
d146d834c2 Add command to paste commit message from clipboard
Resolves #3672
2024-06-26 22:20:54 +02:00
Stefan Haller
68edfa20b4 Add function os.PasteFromClipboard
And a user config to override it with a custom command.
2024-06-26 22:20:54 +02:00
Stefan Haller
bfe9f233ac Convert TranslationSets to json (#3649)
- **PR Description**

This lays the ground for translating lazygit's texts using a translation
system such as Crowdin, Weblate, or Poeditor.

See #3070.
2024-06-23 14:51:03 +02:00
Stefan Haller
741d9a26b6 Change script to write only the English translation set to JSON
We will have to do this regularly in order to upload it to Crowdin (or Weblate
or whatever translation system we are going to use).

Unlike the non-English JSON files, the en.json file is not committed to the git
repo.
2024-06-23 14:47:50 +02:00
Stefan Haller
98e5fd70fb Remove non-English translation sets, read them from JSON instead 2024-06-23 14:47:50 +02:00
Stefan Haller
b34de70c99 Remove all empty strings
I guess I could have coded this into the export script, but I was too lazy and
just did it manually in VS Code, which was easy enough.
2024-06-23 14:47:50 +02:00
Stefan Haller
1e123e2124 Convert the non-English translation sets to JSON files
We write a hacky, one-off script to do that. We need this script only once, so
we don't bother polishing it much. We'll re-purpose it later in the branch to
convert the English translation set to JSON; that is an operation that we need
to do regularly in the future.
2024-06-23 14:47:50 +02:00
Stefan Haller
02aeb6101c Remove unused struct 2024-06-23 14:47:50 +02:00
Stefan Haller
2ccd9980e3 Fix wrong highlight in staging panel when entering file with only staged changes (#3667)
Reproduction recipe:
1. stage all changes in a file by pressing space on it in the files panel
2. enter the staged changes panel by pressing enter
3. unstage one of the changes

This makes the unstaged changes panel visible, but keeps the focus in
the staged changes panel. However, the highlight in the unstaged changes
view becomes visible, as if it were focused.

Fixes #3664
2024-06-23 14:46:36 +02:00
Stefan Haller
db0a1586d9 Highlight inactive selection in bold
An inactive selection is one where the view is part of the context stack, but
not the active view. For example, the files view when you enter the staging
panel, or any view when you open a panel.
2024-06-23 14:43:13 +02:00
Stefan Haller
4e441127f3 Clear highlight in HandleFocusLost
Remove the old mechanism of clearing the highlight in Layout.

This fixes a problem with a wrong highlight showing up in the staging panel when
entering a file with only staged changes.

Reproduction recipe:
1. stage all changes in a file by pressing space on it in the files panel
2. enter the staged changes panel by pressing enter
3. unstage one of the changes
This makes the unstaged changes panel visible, but keeps the focus in the staged
changes panel. However, the highlight in the unstaged changes view becomes
visible, as if it were focused.

To explain why this happens, you need to know how the selection highlighting of
a view is turned on or off. It is turned on when it gains the focus, i.e. when
ActivateFocus is called on it, which in turn happens when PushContext is called.
It is turned off in Layout when gocui sees that the current view is no longer
the same as last time, in which case it calls onViewFocusLost on the previous
current view.

This mechanism only works reliably when there is at most one PushContext call
per event handler. If there is more than one, then the first one gets its
highlight turned on, then the second one, but since gocui has never seen the
first one as the active view in Layout, it doesn't get the highlight turned off
again even though it should.

And this happens in the above scenario. When pressing enter on a file with only
staged changes, we first push the staging context (in
FilesController.EnterFile), and then later we push the stagingSecondary context
when we realize we only have staged changes. This leaves the highlight of the
staging context on.
2024-06-23 13:21:49 +02:00
Stefan Haller
cf40a5b077 Improve render performance (#3686)
- **PR Description**

Fix a performance regression that I introduced with v0.41: when entering
or leaving staging mode for a file, or when switching from a file that
has only unstaged changes to one that has both staged and unstaged
changes, there was a noticeable lag of about 500ms on my machine. With
the improvements in this PR we get this back down to about 20ms.
2024-06-23 13:13:58 +02:00
Stefan Haller
26132cf5bd Use utils.StringWidth to optimize rendering performance
runewidth.StringWidth is an expensive call, even if the input string is pure
ASCII. Improve this by providing a wrapper that short-circuits the call to len
if the input is ASCII.

Benchmark results show that for non-ASCII strings it makes no noticable
difference, but for ASCII strings it provides a more than 200x speedup.

BenchmarkStringWidthAsciiOriginal-10            718135       1637 ns/op
BenchmarkStringWidthAsciiOptimized-10        159197538          7.545 ns/op
BenchmarkStringWidthNonAsciiOriginal-10         486290       2391 ns/op
BenchmarkStringWidthNonAsciiOptimized-10        502286       2383 ns/op
2024-06-23 13:10:48 +02:00
Stefan Haller
a67eda39a5 Rerender fewer views when their width changes
In d5b4f7bb3e and 58a83b0862 we introduced a combined mechanism for rerendering
views when either their width changes (needed for the branches view which
truncates long branch names), or the screen mode (needed for those views that
display more information in half or full screen mode, e.g. the commits view).

This was a bad idea, because it unnecessarily rerenders too many views when just
their width changes, which causes a noticable lag. This is a problem, for
example, when selecting a file in the files panel that has only unstaged
changes, and then going to one that has both staged and unstaged changes; this
splits the main view, causing the side panels to become a bit narrower, and
rerendering all those views took almost 500ms on my machine. Another similar
example is entering or leaving staging mode.

Fix this by being more specific about which views need rerendering under what
conditions; this improves the time it takes to rerender in the above scenarios
from 450-500s down to about 20ms.

This reintroduces the code that was removed in 58a83b0862, but in a slightly
different way.
2024-06-23 13:10:48 +02:00
Stefan Haller
8e1464f720 Don't redraw remote branches view when its width changes
The rendering of remote branches is in no way dependent on the width of the view
(or the screen mode). Unlike in the local branches view, we don't truncate long
branch names here (because there's no more information after them).

This is an error introduced in d5b4f7bb3e.
2024-06-23 13:08:01 +02:00
Stefan Haller
a62a5089d6 Show current value in menus (#3628)
- **PR Description**

Some of our menus let you pick a value for some option (e.g. the sort
order menus for branches and commits). It's nice to see which one is the
current value when opening such a menu, so this PR implements that.

For menus that also have key bindings, the radio button goes between the
key and the label.

As an alternative, I considered selecting the current value when the
menu is opened; however, we currently have no menus where we select a
different entry than the first one, and it might be confusing for people
who are used to opening a menu and then pressing down-arrow a certain
number of times to get to a particular value.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-23 12:56:08 +02:00
Stefan Haller
4967e5136e Show radio buttons in the show log graph and commit sort order menus 2024-06-23 12:53:15 +02:00
Stefan Haller
68c966567c Show radio buttons in the sort order menu for branches 2024-06-23 12:53:15 +02:00
Stefan Haller
20a4aeab6e Support showing checkboxes or radio buttons in menus
For checkboxes it probably doesn't really make sense to use them yet, because
we'd have to find a way how you can toggle them without closing the dialog; but
we already provide rendering for them to lay the ground.

But radio buttons can be used already, because for those it is ok to close the
dialog when choosing a different option (as long as there is only one grounp of
radio buttons in the panel, that is).
2024-06-23 12:53:15 +02:00
Stefan Haller
a5620ebe3a Always show the "Discard unchanged changes" menu item (#3683)
Always show the "Discard unchanged changes" menu item in the Discard
menu, just strike it through if not applicable. This will hopefully help
with confusion about the meaning of "all" in the "Discard all changes"
entry; some people misunderstand this to mean all changes in the working
copy. Seeing the "Discard unstaged changes" item next to it hopefully
makes it clearer that "all" is meant in contrast to that.
2024-06-23 12:46:59 +02:00
Stefan Haller
1b245ef5f6 Always show the "Discard unchanged changes" menu item
Strike it through if not applicable. This will hopefully help with confusion
about the meaning of "all" in the "Discard all changes" entry; some people
misunderstand this to mean all changes in the working copy. Seeing the "Discard
unstaged changes" item next to it hopefully makes it clearer that "all" is meant
in contrast to that.
2024-06-23 12:43:34 +02:00
Stefan Haller
a08c86c182 Fix custom patch operations for added files (#3684)
- **PR Description**

Several custom patch commands on parts of an added file would fail with the
confusing error message "error: new file XXX depends on old contents".
These were dropping the custom patch from the original commit, moving the
patch to a new commit, moving it to a later commit, or moving it to the index.

We fix this by converting the patch header from an added file to a diff against
an empty file. We do this not just for the purpose of applying the patch, but
also for rendering it and copying it to the clip board. I'm not sure it matters
much in these cases, but it does feel more correct for a filtered patch to be
presented this way.

Fixes #3679.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-23 12:43:09 +02:00
Stefan Haller
4cd15a36e3 Fix custom patch operations on added files
Several custom patch commands on parts of an added file would fail with the
confusing error message "error: new file XXX depends on old contents". These
were dropping the custom patch from the original commit, moving the patch to a
new commit, moving it to a later commit, or moving it to the index.

We fix this by converting the patch header from an added file to a diff against
an empty file. We do this not just for the purpose of applying the patch, but
also for rendering it and copying it to the clip board. I'm not sure it matters
much in these cases, but it does feel more correct for a filtered patch to be
presented this way.
2024-06-23 12:40:31 +02:00
Stefan Haller
13a35408e6 Introduce options struct for RenderPatchForFile
We're going to add another argument in the next commit, and that's getting a bit
much, especially when most of the arguments are bool and you only see true and
false at the call sites without knowing what they mean.
2024-06-23 12:40:31 +02:00
Stefan Haller
1a76a7da09 Add test for moving a patch from an added file to an earlier commit
This currently works (albeit with a bit of manual work, as the user needs to
resolve conflicts), and we add this test just to make sure that we don't break
it with the following change.
2024-06-23 12:40:31 +02:00
Stefan Haller
8a16f24ecb Add test for moving a patch from a deleted file to a new commit
This currently works, we add it as a regression test to make sure we don't break
it. It is an interesting test because it turns the deletion of the file in the
moved-from commit into a modification.
2024-06-23 12:40:31 +02:00
Stefan Haller
e2b4d9cff3 Remove unneccesary test actions
Pressing enter in the patch building view does nothing.
2024-06-23 12:40:31 +02:00
Stefan Haller
b2c457366a Fix PTY layout problems (#3658)
- **PR Description**

This fixes two layout problems with pagers that draw a horizontal line
across the entire width of the view (e.g. delta):
- sometimes the width of that line was one character too long or too
short in the staged changes view
- when changing from a file or directory that has only staged or only
unstaged changes to one that has both, the length of the horizontal line
was totally off and only redraw correctly at the next refresh
2024-06-23 12:39:41 +02:00
Stefan Haller
8b8343b8a9 Run PTY tasks after layout so that they get the correct view size
This is important when using a pager that draws a horizontal line across the
entire width of the view; when changing from a file or directory that has only
unstaged (or only staged) changes to one that has both, the main view is split
in half, but the PTY task would be run on the view in its old state, so the
horizonal line would be too long and wrap around.
2024-06-23 12:36:40 +02:00
Stefan Haller
f98da780de Fix possible off-by-one error wrt PTY size
All PTYs were created with the size of the main view, on the assumption that
main and secondary always have the same size. That's not true though; in
horizontal split mode, the width of the two views can differ by one because of
rounding, and when using a pager that draws a horizontal line across the width
of the view, this is visible and looks very ugly.
2024-06-23 12:36:40 +02:00
Stefan Haller
c401f34530 Add prompt to the remote branch checkout menu (#3652)
- **PR Description**

As a followup to [this
discussion](https://github.com/jesseduffield/lazygit/pull/3388#issuecomment-2002308045),
this PR adds a way to add a prompt text to menus. It is shown above the
menu items, separated by a blank line. We use it to add a prompt to the
remote branch checkout menu.
2024-06-23 12:35:50 +02:00
Stefan Haller
ddd6323aa5 Add prompt to the remote branch checkout menu 2024-06-23 12:33:16 +02:00
Stefan Haller
7e92dbfd3d Add menu prompt
This makes it possible to add a prompt to a menu. It will be shown above the
menu items, separated from them by a blank line.
2024-06-23 12:33:16 +02:00
Stefan Haller
dbc21af3b1 Extract function wrapMessageToWidth
This steals even more code from `gocui.lineWrap`.

We'll make use of this in the next commit.
2024-06-23 12:33:15 +02:00
Stefan Haller
6f8244e3fe Fix duplicate keybinding suggestions in status bar after switching repos (#3660)
- **PR Description**

When switching to a repo that was open before, all keybinding
suggestions in the status bar would show twice.

Fixes #3612.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-23 12:31:42 +02:00
Stefan Haller
cf27fd827b Clear keybinding functions in resetHelpersAndControllers
When switching to a repo that was open before, the context tree is reused, so
before adding keybinding functions to those contexts again, we need to clear the
old ones.
2024-06-23 12:28:42 +02:00
Stefan Haller
a7c97400c6 Add a test demonstrating the bug
After switching to another repo and then back to the original one, all
keybinding suggestions in the status bar are shown twice.
2024-06-23 12:28:42 +02:00
Stefan Haller
5e9fe2be80 Fix truncation of branch names containing non-ASCII characters (#3685)
Fix truncating long branch names containing non-ASCII characters.
2024-06-23 12:28:05 +02:00
Stefan Haller
d406ec06af Fix truncation of long branch names containing non-ASCII characters 2024-06-23 12:25:28 +02:00
Stefan Haller
7ec784e2a0 Add test demonstrating wrong truncation of branch names containing non-ASCII characters 2024-06-23 12:25:28 +02:00
Stefan Haller
93af0016f7 Use actual ellipsis character instead of ... to truncate strings
Space is scarce in lazygit's UI, and using ... wastes a lot of it.
2024-06-23 12:25:28 +02:00
Stefan Haller
a171ec4294 Reduce memory consumption when loading large number of commits (#3687)
(Github decided to auto-close #2533, and I don't see any way to reopen
it, so opening a new one here. Please see there for discussion and
review.)

When pressing `>` in the commits panel to trigger loading all the
remaining commits past the initial 300, memory consumption is a pretty
big problem for larger repositories.

The two main causes seem to be
1. the cell memory from rendering the entire list of commits into the
gocui view
2. the pipe sets when git.log.showGraph is on

This PR addresses only the first of these problems, by not rendering the
entire view, but only the visible portion of it. Since we already
re-render the visible portion of the view on every layout call, this was
relatively easy to do.

Below are some measurements for our repository at work (261.985
commits):

|               | master | this PR |
| ------------- | ------ | ------- |
| without Graph | 855 MB | 360 MB  |
| with Graph    | 3.1 GB | 770 MB  |

And for the linux kernel repo (1.170.387 commits):

|               | master                                    | this PR |
| ------------- | ----------------------------------------- | ------- |
| without Graph | 5.8 GB                                    | 1.2G    |
| with Graph    | Killed by the OS after it reached 86.9 GB | 39.9 GB |

The measurements were taken after scrolling all the way down in the list
of commits. They have to be taken with a grain of salt, as memory
consumption fluctuates quite a bit in ways that I find hard to make
sense of.

As you can see, there's more work to do to reduce the memory usage for
the graph, but for our repo at work this PR makes it usable already,
which it wasn't really before.
2024-06-23 12:09:16 +02:00
Stefan Haller
deee5fa957 Render the view when scrolling with the wheel 2024-06-23 11:54:21 +02:00
Stefan Haller
44160ef844 Only render visible portion of the screen for commits view 2024-06-23 11:54:21 +02:00
Stefan Haller
dd2bffc278 Simplify ListContextTrait.FocusLine
When refreshViewportOnChange is true, we would refresh the viewport once at the
end of FocusLine, and then we would check at the end of AfterLayout if the
origin has changed, and refresh again if so. That's unnecessarily complicated,
let's just unconditionally refresh at the end of AfterLayout only.
2024-06-23 11:54:21 +02:00
Stefan Haller
9eb9b369ff Bump gocui 2024-06-23 11:54:01 +02:00
Stefan Haller
fafa4280f5 Log memory usage every 10s 2024-06-23 11:48:40 +02:00
Stefan Haller
5a5cd849d1 Search the model instead of the view in the commits panel (#3642)
- **PR Description**

This makes it possible to search the model data instead of the view when
pressing `/`, and uses this for the commits view.

This is mainly a preparation for #2533 which requires it, but it is also
useful on its own, because it makes it possible to search for full
commit hashes. It will highlight the abbreviated hash in that case.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-23 11:48:00 +02:00
Stefan Haller
6a6316cfb6 Use model searching in commits (and sub-commits) view 2024-06-23 11:43:12 +02:00
Stefan Haller
779e6f95a3 Assert that the search status view is visible
Just to be really sure that it not only contains the expected status text, but
also actually shows it.
2024-06-23 11:43:12 +02:00
Stefan Haller
44ad36bb39 Add type assertions for all searchable contexts
We want to add an additional method to ISearchableContext later in this branch,
and this will make sure that we don't forget to implement it in any concrete
context.
2024-06-23 11:43:12 +02:00
Stefan Haller
08a8b067a5 Cleanup: remove outdated comment
We do show the graph in the left/right view, as of b7673577a2.
2024-06-23 11:43:12 +02:00
Stefan Haller
15b25b5afb Fix searching in the divergence (left/right) view
Searching in the "Divergence from upstream" view would select the wrong lines.
The OnSearchSelect function gets passed a view index, and uses it to select a
model line. In most views these are the same, but not in the divergence view
(because of the Remote/Local section headers).
2024-06-23 11:43:12 +02:00
Stefan Haller
27ad75de16 Cleanup: reduce some code duplication
ListContextTrait.OnSearchSelect was introduced in 138be04e65, but it was never
called. I can only guess that a planned refactoring wasn't finished here.
2024-06-23 11:43:12 +02:00
Stefan Haller
3af545daf7 Add user config gui.commitAuthorFormat (#3625)
- **PR Description**
Adds configuration option defining whether to show full author names or
their shortened form in the commit graph.

Closes [#3624](https://github.com/jesseduffield/lazygit/issues/3624).

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-15 16:17:48 +02:00
anikiforov
57f9493770 Add user config gui.commitAuthorFormat 2024-06-15 10:39:50 +04:00
Stefan Haller
629b7ba1b8 Fix reporting of unexpected selections in integration tests (#3662)
Expected and actual selection were swapped in the error message.
2024-06-14 13:36:45 +02:00
Stefan Haller
43e04febee Fix reporting of unexpected selections in integration tests
Expected and actual selection were swapped in the error message.
2024-06-14 13:26:14 +02:00
Stefan Haller
c08a5fe4e7 Show "exec" todos in the list of rebase todos (#3654)
- **PR Description**

It is sometimes useful to perform a `git rebase -x "make test"
origin/main` in order to verify that all commits of the current branch
are green. However, if the rebase stops in the middle because one of
those tests fail, it's easy to accidentally press `m <enter>` in lazygit
after amending some fix, not realizing that the rest of the tests will
now run invisibly inside lazygit.

This PR makes two changes to improve this situation:
- It shows exec todos in the commits panel: 
<img width="482" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/1225667/608b24e8-9f3d-4a5f-9bb5-e16268c86e83">
- when continuing a rebase and there are exec todos, it suspends itself
to the background so that you can see the output of the test runs in the
terminal.

We can improve this further in the future; for example, it would often
be useful to be able to delete some of the exec commands, this is not
currently possible. But it's still better than before.
2024-06-12 14:38:44 +02:00
Stefan Haller
92dd80c3e3 Suspend lazygit when continuing a rebase with exec todos
It's likely that the exec todos are some kind of lengthy build task whose output
the user will want to see in the terminal.
2024-06-12 12:45:00 +02:00
Stefan Haller
899e25b208 Show "exec" todos in the list of rebase todos
Unfortunately it isn't possible to delete them. This would often be useful, but
our todo rewriting mechanisms rely on being able to find todos by some
identifier (hash for pick, ref for update-ref), and exec todos don't have a
unique identifier.
2024-06-12 12:44:33 +02:00
Stefan Haller
906d21f3ce Improve "Find base commit for fixup" command when there are changes for master commits (#3645)
- **PR Description**

If exactly one candidate from inside the current branch is found, we
return that one even if there are also hunks belonging to master
commits; we disregard those in this case.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-10 12:03:22 +02:00
Stefan Haller
7780f1264a Disregard master commits when finding base commit for fixup
If exactly one candidate from inside the current branch is found, we return that
one even if there are also hunks belonging to master commits; we disregard those
in this case.
2024-06-10 12:00:24 +02:00
Stefan Haller
f3718ddfb0 Don't reference Model().Commits multiple times
Copy the slice into a variable and use that throughout the whole operation; this
makes us a little more robust against the model refreshing concurrently.
2024-06-10 12:00:24 +02:00
Stefan Haller
f9ba2dac9d Add test demonstrating the desired behavior
It has two modified hunks, one for a master commit and one for a branch commit.
Currently we get an error mentioning those two commits, but we would like to
silently select the branch commit.
2024-06-10 12:00:24 +02:00
Stefan Haller
6cb2ac6fcc Support range select for amending commit attributes (#3587)
- **PR Description**

This PR makes it possible for users to select a range of commits from
the commits view to amend their attributes (set/reset author, add
co-author), the same way it's already possible to do for a single
commit.

It closes #3273. 

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-07 23:28:54 +02:00
AzraelSec
6b9cf72e79 feat: support range selection for commit attributes amend 2024-06-07 23:09:52 +02:00
Stefan Haller
92f13fc56e Fix secondary window resize (#3637)
- **PR Description**
This PR fixes the behavior the staging secondary panel (staged lines)
currently has in relation to changing its view mode. In particular,
these changes allows the users to expand the secondary panels the same
way all the others do.

This closes #3629.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-07 22:54:25 +02:00
AzraelSec
06496ccd17 feat: let the staging secondary panel change view mode 2024-06-07 22:51:16 +02:00
AzraelSec
03a075c223 fix: typo in IsVisible assertion string 2024-06-07 22:51:16 +02:00
Stefan Haller
eef70dbdf6 Include demos when running integration tests on CI (#3640)
- **PR Description**

This includes the demos when using `make integration-test-all`, and
speeds them up a little bit when run in this way by disabling Wait calls
when running in headless mode.

This will guard against demos breaking when we make behavior changes, as
happened several times in the past (most recently in #3636.
2024-06-05 15:00:25 +02:00
Stefan Haller
f5329440fc Include demos when running integration tests with go test 2024-06-05 14:44:02 +02:00
Stefan Haller
4f6d3fb592 Don't wait in integration tests when running in headless mode
There's no point in spending time waiting in this case, as nobody can see it.
2024-06-05 14:44:02 +02:00
Stefan Haller
187a2f0cc2 Update rebase_onto demo test to match new the rebase menu title (#3636)
- **PR Description**

This PR updates the `rebase_onto` demo integration test, which is
currently failing on master due to [this
change](https://github.com/jesseduffield/lazygit/pull/3615/files#diff-3eb5426752dae525c92f1ecce2f7215d15bfdec91bd459e08f78574876583910R1259).
Our CI does not throw the issue, but it's still annoying to cope with it
for local development.

@jesseduffield @stefanhaller, I'm unaware of a particular workflow for
updating demo tests, but let me know if this needs some tweaks.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs have been updated if necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-06-05 14:43:44 +02:00
AzraelSec
f6457c4def fix: update rebase_onto demo test to match new rebase menu title 2024-06-05 01:38:08 +02:00
Stefan Haller
66a04e4273 Make profiling easier (#3634)
Add a `-profile` command line flag, and some documentation about how to
collect and view profile data.
2024-06-04 15:41:25 +02:00
Stefan Haller
ffedd84e92 Add some developer documentation about profiling 2024-06-04 15:37:59 +02:00
Stefan Haller
ab0b0da850 Add -profile command line flag
When on, start a built-in web server that takes requests on port 6060 to gather
profiling data.
2024-06-03 19:07:24 +02:00
Stefan Haller
b85687797d Add command to rebase onto base branch (#3615)
- **PR Description**

In the rebase menu, add a command "Rebase onto base branch". This makes
it more convenient to rebase onto master (or main), because
- you don't need to bring your local version of the base branch up to
date first
- you don't have to remember which of your main branches (e.g. "main",
"devel", or "1.0-hotfixes") your current branch is based on.

This is sitting on top of #3614.

Closes #3546.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-03 14:09:24 +02:00
Stefan Haller
a8921a13cb Add command "Rebase onto base branch" to rebase menu 2024-06-03 14:06:11 +02:00
Stefan Haller
837f7456ab Remove target branch from title of rebase menu
Put it into the individual menu items instead.

Again, this is necessary because we are going to add another entry to the menu
that is independent of the selected branch.
2024-06-03 14:06:11 +02:00
Stefan Haller
ddf5e24499 Always show rebase menu, even when rebasing is not possible
Instead, disable the individual entries in the menu.

This is necessary because we are going to add another entry to the menu that is
independent of the selected branch.
2024-06-03 14:06:11 +02:00
Stefan Haller
ca6d88080c Make "Rebase" show up with "..." in the keybindings menu 2024-06-03 14:06:11 +02:00
Stefan Haller
1b7ded6df3 Fix typo 2024-06-03 14:06:11 +02:00
Stefan Haller
36a4696573 Add command to show divergence from base branch as a left-right log (#3614)
- **PR Description**

Add a command similar to the existing "Show divergence from upstream",
but for the base branch instead. Useful to see what you would rebase
onto if you were to rebase onto the base branch now.

It could be considered somewhat questionable that we display both the
Remote and Local sections of the log here; the Local section isn't
really interesting because it's always identical to what you see in the
Commits view. I chose to still show it since it makes the divergence
view look more familiar, and I think overall it makes it clearer what
you're looking at.

This is sitting on top of #3613 and uses some of the code that was added
there.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-03 14:05:39 +02:00
Stefan Haller
343db7b3f1 Add command "View divergence from base branch" 2024-06-03 14:02:07 +02:00
Stefan Haller
4ac77f4575 Divergence from base branch display (#3613)
- **PR Description**

Add a new config option `showDivergenceFromBaseBranch`; if not "none",
it indicates in the branches view for each branch if it has fallen
behind its base branch, and optionally by how much. If set to
"onlyArrow", it will append `↓` after the branch status; if set to
"arrowAndNumber", it appends `↓17`, where the count indicates how many
commits it is behind the base branch. These are colored in blue, and go
after the existing yellow `↓3↑7` indication of divergence from the
upstream.

The option is off by default, since we are afraid that people may find
this too noisy. We may reconsider this choice in the future if the
response is positive.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-03 14:01:43 +02:00
Stefan Haller
373b1970ca Show divergence from base branch in branches list 2024-06-03 13:59:43 +02:00
Stefan Haller
5b613f5bc7 Remove ColoredBranchStatus and branchStatusColor
Previously the entire status was colored in a single color, so the API made
sense. This is going to change in the next commit, so now we must include the
color in the string returned from BranchStatus(), which means that callers who
need to do hit detection or measure the length need to decolorize it.

While we're at it, switch the order of ↑3↓7 to ↓7↑3. For some reason that I
can't really explain I find it more logical this way. The software out there is
pretty undecided about it, it seems: VS Code puts ↓7 first, and so does the
shell prompt that comes with git; git status and git branch -v put "ahead" first
though. Shrug.
2024-06-03 13:02:46 +02:00
Stefan Haller
8c385731f7 Add GetBaseBranch function 2024-06-03 13:02:46 +02:00
Stefan Haller
e79b4259e4 Make GetMergeBase a method of ExistingMainBranches 2024-06-03 13:02:46 +02:00
Stefan Haller
f4d922bc80 Factor out CommitLoader.mainBranches into its own class, and store it in Model 2024-06-03 13:02:46 +02:00
Stefan Haller
b2011dca35 Remove the cache invalidation logic from getMergeBase
It is a valid case for a branch to share no history with any of the main
branches, in which case git merge-base returns an error (and an empty string).
Since we can't distinguish this from one of the main branches having been
deleted, we shouldn't invalidate the cache in that case.
2024-06-03 13:02:46 +02:00
Stefan Haller
19d0048cc4 More explicit test of status panel content
Use Equals instead of Contains for asserting the status view content. This
solves the problem that we might assert Contains("↓2 repo"), but what it really
shows is "↑1↓2 repo", and the test still succeeds. At best this is confusing.

Also, this way we don't have to use the awkward DoesNotContain to check that it
really doesn't show a checkmark.

To do this, we need to fix two whitespace problems:
- there was always a space at the end for no reason. Simply remove it. It was
  added in efb51eee96, but from looking at that diff it seems it was added
  accidentally.
- there was a space at the beginning if the branch status was empty. This is
  actually a cosmetic problem, for branches without a status the text was
  indented by once space. Change this so that the space is added conditionally.
  It's a bit awkward that we have to use Decolorise here, but this will go away
  again later in this branch.
2024-06-03 13:02:46 +02:00
Stefan Haller
7c51ec21bf (#3618) Fix pushing a branch to remote with a different name causing error (#3630)
- **PR Description**

This fixes an error where, given the user wants push a branch to a
remote branch with a different name, the following error would be
presented:

```
Error
error: src refspec <desired remote branch name> does not match any
error: failed to push some refs to <remote .git URI>
```


- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-02 09:05:20 +02:00
Jordan
39ea5d9ab1 Add HEAD: when referencing upstream branch
Update unit tests
2024-06-02 09:02:33 +02:00
Stefan Haller
205357a44f Improve the "Find base commit for fixup" command (#3602)
- **PR Description**

Improve the `ctrl-f` command so that it also works when there are no
hunks with deleted lines in the diff. This is very useful, for example,
when a fixup commit adds a comment to a function that was added in the
PR.

Since the exact behavior of the command is getting very complex and hard
to understand, I added a design document that describes what it does,
and also how it differs from git-absorb which does a very similar thing.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-01 19:56:50 +02:00
Stefan Haller
c9c556beba Update user doc 2024-06-01 08:31:18 +02:00
Stefan Haller
b82c72b63d Add design document for "Find base commit for fixup"
This document explains why we made certain decisions about the behavior of the
command. This is too detailed for users, but could be useful in the future if we
want to discuss further improvements.
2024-06-01 08:31:18 +02:00
Stefan Haller
dbdabb34f3 Make "Find base commit for fixup" work with hunks with only added lines
To understand what this does and why, read the design document that I'm about to
add in the next commit.
2024-06-01 08:31:18 +02:00
Stefan Haller
c1a65546ad Extract a function findCommit
It's not much code, but it turns three lines of code into one, and since we need
to do this a few more times in the next commit, it's worth it.
2024-06-01 08:31:18 +02:00
Stefan Haller
2c9bca8b57 Return errors from blameDeletedLines instead of just logging them
I guess when I originally wrote this code I just didn't know how to do that...
2024-06-01 08:31:18 +02:00
Stefan Haller
880528b2e4 Also return hunks with only added lines from parseDiff
We aren't using them, yet, except for deciding whether to show the warning about
hunks with only added lines.

Add a bit of test coverage for parseDiff while we're at it.
2024-06-01 08:31:18 +02:00
Stefan Haller
e1b4d625c7 Make parseDiff a non-member function so that we can test it more easily 2024-06-01 08:31:18 +02:00
Stefan Haller
a957c5542f Rename deletedLineInfo to hunk
We'll use it with a more general meaning later in this branch.
2024-06-01 08:31:18 +02:00
Stefan Haller
f085d10c46 Add user config gui.expandedSidePanelWeight (#3623)
- **PR Description**

Add a user config `gui.expandedSidePanelWeight` which lets you change
the default weight of 2 that gets assigned to the expanded side panel if
`expandFocusedSidePanel` is true.

Closes #3621.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-06-01 08:25:30 +02:00
Stefan Haller
1269938ee6 Add user config expandedSidePanelWeight 2024-06-01 08:21:23 +02:00
Stefan Haller
557dfc5a6d Add test for ExpandFocusedSidePanel config 2024-06-01 08:16:06 +02:00
Stefan Haller
c5baa5da3a Fix pushing to branch when upstream not stored locally (#3619)
- **PR Description**

This fixes three different problems; two were recent regressions, one
has never worked.

1. For branches whose remote is not stored locally, don't ask to force
push right away. Try a normal push first. This broke with #3528.
2. For branches whose remote is not stored locally (but only for those),
if the server rejects the update, ask to force push. This broke with
#3387.
3. When force-pushing a branch whose remote is not stored locally, use
`--force` instead of `--force-with-lease`; otherwise the push would
always fail with a "stale info" error. This has never worked.

Fixes #3588.
2024-06-01 08:15:35 +02:00
Stefan Haller
3284d69886 Add integration test for pushing when the remote is not stored locally
The test needs all three fixes from this branch to succeed.
2024-06-01 08:12:45 +02:00
Stefan Haller
116c18e957 Use --force instead of --force-with-lease when remote is not stored locally
--force-with-lease simply doesn't work in this case, it will always return a
"stale info" error.
2024-06-01 08:12:45 +02:00
Stefan Haller
e93617b1de Rename Force to ForceWithLease
This describes better what it is, and we're going to add the regular --force in
the next commit.

No change in behavior in this commit.
2024-06-01 08:12:45 +02:00
Stefan Haller
aac2535104 Ask to force push if server rejected the update, if remote not stored locally
This broke with 81b497d186 (#3387). In that PR I claimed that we never want to
ask for force-pushing if the server rejected the update, on the assumption that
this can only happen because the remote tracking branch is not up to date, and
users should just fetch in this case. However, I didn't realize it's even
possible to have a branch whose upstream branch is not stored locally; in this
case we can't tell ahead of time whether a force push is going to be necessary,
so we _have_ to rely on the server response to find out. But we only want to do
that in this specific case, so this is not quite an exact revert of 81b497d186.
2024-06-01 08:12:45 +02:00
Stefan Haller
993d66a8ff Don't force-push if the remote branch is not stored locally
This broke with #3528.

If the remote branch is not stored locally, we only see question marks in the
branch status. In this case we can't tell whether we need to force-push, so it's
best to assume that we don't, and see if the server rejects the push, and react
to that by asking to force push. This second part is also broken right now,
we'll fix this in the next commit.
2024-06-01 08:12:45 +02:00
Stefan Haller
ab797fe986 Fix boolean config keys not appearing in the generated Config.md (#3622)
- **PR Description**

All boolean config keys were missing from the generated Config.md.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-05-31 21:29:17 +02:00
Stefan Haller
4bfda1a78c Fix boolean config keys not appearing in the generated Config.md
The reason why they didn't appear is that they didn't get a default value in the
generated schema; this commit fixes that.
2024-05-31 20:07:58 +02:00
Stefan Haller
91cb33db85 Remove an outdated comment
Lazygit doesn't touch this, the comment is just not true.

I wonder if we need the config at all, actually; I'd be in favor of removing it.
2024-05-31 20:05:44 +02:00
Stefan Haller
7492521829 Improve branch and reflog loading when sorting branches by date (#3609)
- **PR Description**

When branches are sorted by recency we have this logic that first loads the
branches so that they can be rendered quickly; in parallel, it starts loading
the reflog in the background, and when that's done, it loads the branches again
so that they get their recency values. This means that branches are loaded twice
at startup.

We don't need this logic when branches are not sorted by recency, so we can
simply load branches and reflog in parallel like everything else.

This shouldn't change any user observable behavior, it just avoids doing
unnecessary work at startup.
2024-05-29 13:50:02 +02:00
Stefan Haller
35af886f55 Refresh branches and reflog independently when sorting branches by date
When branches are sorted by recency we have this logic that first loads the
branches so that they can be rendered quickly; in parallel, it starts loading
the reflog in the background, and when that's done, it loads the branches again
so that they get their recency values. This means that branches are loaded twice
at startup.

We don't need this logic when branches are not sorted by recency, so we can
simply load branches and reflog in parallel like everything else.

This shouldn't change any user observable behavior, it just avoids doing
unnecessary work at startup.
2024-05-29 13:46:53 +02:00
Stefan Haller
f45ecbc19a Fix out-of-date comment
The behavior described in the comment is no longer what we do, it was changed in
ae66f720f5; we now always reuse the state.
2024-05-29 13:46:53 +02:00
Stefan Haller
51eb6d7c7d Pin golangci version to 1.58 (#3611)
Pin golangci version to 1.58.

It is annoying when CI builds suddenly start to fail because the linter
was updated and finds new things to complain about.

Updating the linter and fixing the code accordingly should be a
dedicated activity.
2024-05-29 13:46:19 +02:00
Stefan Haller
38ec4e646f Pin golangci version to 1.58
It is annoying when CI builds suddenly start to fail because the linter was
updated and finds new things to complain about.

Updating the linter and fixing the code accordingly should be a dedicated
activity.
2024-05-29 13:42:11 +02:00
Stefan Haller
ef1daf314a Fix tooltip for fixup command (#3601)
### PR Description

- Fix calculation of tooltip height; for tooltips that are just one or
two characters longer than the available width, the last word would be
cut off. On my screen this happened for the tooltip for the fixup
command.
- Fix tooltip of fixup command.

Fixes #3600.
2024-05-27 07:53:16 +02:00
Stefan Haller
ab643749e8 Fix tooltip of fixup command 2024-05-26 19:30:38 +02:00
Stefan Haller
2d0c96466a Fix calculation of tooltip height
For tooltips that are just one or two characters longer than the available
width, the last word would be cut off. On my screen this happened for the
tooltip for the fixup command.
2024-05-26 19:26:27 +02:00
Jesse Duffield
f6ace8380f Update readme 2024-05-26 14:35:38 +10:00
Stefan Haller
b4aa68d0b3 Delete the TODO comment about enabling goconst in the future from .golangci.yml (#3596)
## Context:

https://github.com/jesseduffield/lazygit/pull/3592#issuecomment-2129535231
2024-05-24 15:40:41 +02:00
kyu08
4a97fb80f3 Delete the TODO comment about enabling goconst in the future from .golangci.yml 2024-05-24 22:29:44 +09:00
Stefan Haller
8f1a04d095 Add lint to make target (#3593)
I feel this is necessary when I worked on
https://github.com/jesseduffield/lazygit/pull/3592.
2024-05-24 12:57:47 +02:00
kyu08
e5f4de8d34 Add lint to make target 2024-05-24 12:54:45 +02:00
Stefan Haller
ce3fe37787 Add copyloopvar to enabled linters (#3586)
Resolves #3573 
It looks like the update to go1.22 is done by
https://github.com/jesseduffield/lazygit/pull/3574. So it should be OK
to close #3573 when this PR is merged.

## PR Description
Add [`copyloopvar`](https://github.com/karamaru-alpha/copyloopvar) to
enabled linters to detect unnecessary assignments in `for` loops.

## Context
@jesseduffield and I were talking about necessity of this linter here.
https://github.com/jesseduffield/lazygit/issues/3573#issuecomment-2123732829
2024-05-24 11:03:01 +02:00
kyu08
6cf6941a77 Add copyloopvar to enabled linters 2024-05-22 21:57:34 +09:00
Stefan Haller
0fbed71f15 Add property outputTitle to CustomCommand (#3579)
- **PR Description**

Add property `outputTitle` to CustomCommand. It can optionally be used
to set the title of the panel that shows the output of a command (when
`showOutput` is true). If left unset, the command string is used as the
title.

Closes #3576.
2024-05-20 21:05:58 +02:00
Stefan Haller
22a38c9f50 Add property outputTitle to CustomCommand
It can optionally be used to set the title of the panel that shows the output of
a command (when showOutput is true). If left unset, the command string is used
as the title.
2024-05-20 21:02:49 +02:00
Stefan Haller
6343fb57d6 Focus on local commits view after moving code into new commit (#3577)
- **PR Description**

This PR forces lazygit to focus to the `Commits` view after moving a
custom (partial) patch in a new commit.

This closes #3200.
2024-05-20 20:58:31 +02:00
AzraelSec
5af0ea85fc feat: focus on local commits view after moving code into new commit 2024-05-20 19:12:38 +02:00
Stefan Haller
a4e9181a6b Remove hint about Config.md from PR template (#3578)
It used to be a common thing to have to update `Config.md` in a PR (and
we often forgot despite the template). As of #3565 this is no longer
necessary, so remove this from the template.

Updating docs in general is still a good thing to think about, so we
leave this in.
2024-05-20 07:01:30 +02:00
Stefan Haller
f5d57f7cc7 Remove hint about Config.md from PR template
It used to be a common thing to have to update Config.md in a PR (and we often
forgot despite the template). As of #3565 this is no longer necessary, so remove
this from the template.

Updating docs in general is still a good thing to think about, so we leave this
in.
2024-05-20 06:59:22 +02:00
Jesse Duffield
fc7b10f557 Update README.md
Updated the company sponsors with the new name of my company
2024-05-20 12:21:07 +10:00
Stefan Haller
b75c177c31 Add default lazygit config generation in Config.md from JSON schema (#3565)
- **PR Description**
This uses the JSON schema generated in
https://github.com/jesseduffield/lazygit/pull/3039 to generate and
replace the default lazygit config in Config.md when running `go
generate ./...`

Relevant issue: https://github.com/jesseduffield/lazygit/issues/3441

The generated config contains all the entries that have default values
set in `user_config.go`
2024-05-19 14:11:23 +02:00
Karim Khaleel
9b152d7619 Make Keybindings definition in UserConfig struct last
This makes the generated default config in Config.md match the original
order.
2024-05-19 14:08:27 +02:00
Karim Khaleel
b98ae1c773 Add default lazygit config generator for Config.md from JSON schema 2024-05-19 14:08:05 +02:00
Karim Khaleel
7d787afb2c Set default value for WindowSize config to pass validation 2024-05-19 14:07:51 +02:00
Karim Khaleel
af842e40d4 Remove unnecesary schema validations in user config 2024-05-19 14:07:40 +02:00
Stefan Haller
6fcb7eb8bb Correctly request force-pushing in a triangular workflow (#3528)
- **PR Description**

Some people push to a different branch (or even remote) than they pull
from. One example is described in #3437. Our logic of when to request a
force push is not appropriate for these workflows: we check the
configured upstream branch for divergence, but that's the one you pull
from. We should instead check the push-to branch for divergence.

Fixes #3437.
2024-05-19 10:00:32 +02:00
Stefan Haller
c5cf1b2428 Correctly request force-pushing in triangular workflows
To determine whether we need to ask for force pushing, we need to query the push
branch rather than the upstream branch, in case they are not the same.
2024-05-19 09:44:38 +02:00
Stefan Haller
d890c68cd0 Add ahead/behind information for @{push}
In a triangular workflow the branch that you're pulling from is not the same as
the one that you are pushing to. For example, some people find it useful to set
the upstream branch to origin/master so that pulling effectively rebases onto
master, and set the push.default git config to "current" so that "feature"
pushes to origin/feature.

Another example is a fork-based workflow where "feature" has upstream set to
upstream/main, and the repo has remote.pushDefault set to "origin", so pushing
on "feature" pushes to origin/feature.

This commit adds new fields to models.Branch that store the ahead/behind
information against the push branch; for the "normal" workflow where you pull
and push from/to the upstream branch, AheadForPush/BehindForPush will be the
same as AheadForPull/BehindForPull.
2024-05-19 09:44:38 +02:00
Stefan Haller
0aba686f97 Rename Pushables/Pullables to AheadForPull/BehindForPull
In preparation for adding AheadForPush/BehindForPush in the next commit.
2024-05-19 09:44:38 +02:00
Stefan Haller
b91b40ba4d Add test demonstrating the problem with force-pushing in a triangular workflow
Our code doesn't realize that we need to prompt the user to force push, when the
branch is up-to-date with its upstream but not with the branch that we're
pushing to.
2024-05-19 09:44:38 +02:00
Stefan Haller
c4927e21c5 Rename PushBranch to PushBranchAndSetUpstream
It is unexpected that a function called PushBranch also sets the upstream
branch; also, we want to add a PushBranch function in the next commit that
doesn't.
2024-05-19 09:44:38 +02:00
Stefan Haller
6afcc5bda8 Create shims for all model classes in SessionStateLoader
This guards against accidentally renaming a model field and thereby breaking
user's custom commands. With this change we'll get a build failure when we do
that.
2024-05-19 09:44:38 +02:00
Jesse Duffield
9fc7a5177b Bump go version to 1.22 (#3574)
- **PR Description**

Bumps go from 1.21 to 1.22, and removes newly redundant loop variable
re-declarations now that in 1.22 the variables are automatically
redeclared in each iteration for us.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-05-19 17:22:42 +10:00
Jesse Duffield
fdff2dec79 Remove redundant variable dedeclarations
In go 1.22, loop variables are redeclared with each iteration of the
loop, rather than simple updated on each iteration. This means that we
no longer need to manually redeclare variables when they're closed over
by a function.
2024-05-19 16:38:21 +10:00
Jesse Duffield
9124d8dbaa Bump go version to 1.22 2024-05-19 16:38:21 +10:00
Jesse Duffield
4404aacdee README.md: Update Sponsors (#3503)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-05-19 16:15:32 +10:00
github-actions[bot]
8f5ce14dc0 README.md: Update Sponsors 2024-05-19 05:09:25 +00:00
Stefan Haller
866e80529b Delete and edit custom commands history items (#3534)
- **PR Description**

Allow deleting and editing custom command history items. Deleting is
done by hitting `d` on a suggestion; editing is done by hitting `e`,
which fills the selected item into the command prompt for further
editing.

Closes #2528.
2024-05-19 07:09:13 +02:00
Stefan Haller
010b0ae923 Show delete/edit keybindings in suggestions subtitle if available 2024-05-19 07:06:18 +02:00
Stefan Haller
a7041cf492 Allow editing a custom command from the suggestions list by pressing 'e'
For custom commands it is useful to select an earlier command and have it copied
to the prompt for further editing. This can be done by hitting 'e' now.

For other types of suggestion panels we don't enable this behavior, as you can't
create arbitrary new items there that don't already exist as a suggestion.
2024-05-19 07:06:18 +02:00
Stefan Haller
da3e0f7147 Support deleting items from the custom commands history
In the custom commands panel you can now tab to the suggestions and hit 'd' to
delete items from there. Useful if you mistyped a command and don't want it to
appear in your history any more.
2024-05-19 07:06:18 +02:00
Jesse Duffield
269d01233f Improve nvim-remote mode (#3508)
- If _not_ inside a neovim session, treat as a normal nvim invocation
and suspend lazygit.

- If inside a neovim session:
  - Do not try to suspend lazygit.
  - Send `q` keystroke to neovim session to quit lazygit.
  - Send filename/line/etc. to neovim session.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-05-19 14:42:47 +10:00
Charlie Moog
615ff09afa improve nvim-remote mode
- If _not_ inside a neovim session, treat as
  a normal nvim session and suspend lazygit.

- If inside a neovim session:
  - Do not try to suspend lazygit.
  - Send `q` keystroke to neovim session to quit lazygit.
  - Send filename/line/etc. to neovim session.
2024-05-19 14:39:02 +10:00
Jesse Duffield
772388294a Attempt #2 at preventing codacy coverage step from running on forks (#3572)
- **PR Description**

First attempt didn't work. Let's try this one, based on
https://github.com/orgs/community/discussions/25217

<img width="910" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/8456633/fa2e82b0-db34-486b-8bea-ec3807d10a33">

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-05-19 14:38:48 +10:00
Jesse Duffield
e09b38153c Attempt #2 at preventing codacy coverage step from running on forks 2024-05-19 14:36:25 +10:00
Jesse Duffield
cd62c719f1 Only run code coverage report on non-fork branches (#3571)
- **PR Description**

Codacy's coverage report feature requires the use of a secret key, which
is only available on the main repo and is not available on forks. So,
the step has been always failing on any forks. This commit ensures that
we only run it on non-forks.

This greatly diminishes the value of the coverage reports. I've talked
to one of the Codacy people and advised that they should just have an
API key for coverage reports which is not a secret, like what bugsnag
does.

I've disabled the gate in codacy meaning if the coverage ever drops
beneath some percentage, the job won't fail. It wouldn't make sense to
fail the job if some other PR from a fork was responsible for reducing
the coverage percentage beneath some threshold.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-05-19 14:10:16 +10:00
Jesse Duffield
36e7524146 Only run code coverage report on non-fork branches
Codacy's coverage report feature requires the use of a secret key, which
is only available on the main repo and is not available on forks. So,
the step has been always failing on any forks. This commit ensures that
we only run it on non-forks.

This greatly diminishes the value of the coverage reports. I've talked
to one of the Codacy people and advised that they should just have an
API key for coverage reports which is not a secret, like what bugsnag
does.
2024-05-19 14:05:30 +10:00
Stefan Haller
189f39de2b Fix Stashing partial files for git version >= 2.35.0 (#3569)
- **PR Description**
Use git's `--staged` flag to stash staged changes if available (requires
git 2.35.0 or later), and fall back to our previous method if not. This
is a lot faster than our previous method, and it fixes two bugs, see
linked issues.

Fixes #3333 and #3563.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-05-18 10:07:24 +02:00
dsolerhww
5b80c0c792 Fix stashing partialy staged files for git version >= 2.35.0
Use `git stash push --staged` git feature available on git version >
2.35.0.
2024-05-18 09:59:00 +02:00
Stefan Haller
d8b3c0e568 Fix loading commits with very long subjects (#3533)
- **PR Description**

This PR fixes a problem with lazygit locking up completely when there's
a commit whose subject line is longer than approximately 65500
characters.

Fixes #3529.
2024-05-15 13:29:28 +02:00
Stefan Haller
f69eb6dc48 Use ScanLinesAndTruncateWhenLongerThanBuffer instead of bufio.ScanLines 2024-05-15 13:27:01 +02:00
Stefan Haller
e0a2d97f0f Put subject last in git log's prettyFormat
We are going to truncate overly long lines returned from git log, and the most
likely field that is going to make the line too long is the subject; so we must
put it last, otherwise we'd end up with not enough fields to split when it's too
long.

It might not be obvious from the diff what's happening to the mock command
output in the test: it didn't have the divergence field (">") at all, which was
kind of a bug. It didn't matter for these tests though, because we are not
testing the divergence here, and our production code happens to be resilient
against it missing. But now we must add the ">" field before the subject.
2024-05-15 13:27:01 +02:00
Stefan Haller
66d0ce841c Implement ScanLinesAndTruncateWhenLongerThanBuffer 2024-05-15 13:27:01 +02:00
Stefan Haller
6bb8c180b2 Handle scanner error in RunAndProcessLines
Scanners can return errors (e.g. ErrTooLong), and if we don't handle it, the
cmd.Wait() call below will block forever because nobody drains the command's
output.

This happens for CommitLoader.GetCommits when there's a commit whose subject
line is longer than approx. 65500 characters; in that case, lazygit would lock
up completely. With this fix it remains usable, but the commit list is truncated
before the bad commit, which is not good enough. We'll improve that in the
remaining commits of this branch.
2024-05-15 13:27:01 +02:00
Stefan Haller
5558d873af Fix clicking in status side panel (#3547)
- **PR Description**

Clicking in the status side panel should activate it; also, clicking on
the repo name should bring up the recent repositories menu, and clicking
on the "(rebasing)" text should bring up the rebase options menu. All of
this was broken for a long time, since somewhere around the big
refactoring of March 2023. (The exact commit where it broke is hard to
bisect, since many of the commits in that area either don't compile or
crash at startup...)

I'm fixing this not because I think it's super important functionality
(nobody seems to have missed it for over a year), but because I have to
touch this code in another PR, and noticed that it wasn't working.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-05-15 13:24:07 +02:00
Stefan Haller
380855d4e8 Add tests for clicking in status side panel
To prevent this from breaking again. All three tests would fail without the fix
from the previous commit.
2024-05-15 13:21:17 +02:00
Stefan Haller
88e7c44552 Fix clicking in status side panel
Seems to have been broken since that big refactoring in March 23.
2024-05-15 13:21:17 +02:00
Stefan Haller
ac0524f7cb Fix deadlock reporting (#3550)
Deadlock reporting broke in e1ceb6892a (last September); since then, it
was *off* when running debug builds normally, but *on* when debugging an
integration test. Both of which are exactly opposite of what we want.
2024-05-15 13:19:41 +02:00
Stefan Haller
10e29ce7dd Fix deadlock reporting
Deadlock reporting broke in e1ceb6892a; since then, it was *off* when running
debug builds normally, but *on* when debugging an integration test. Both of
which are exactly opposite of what we want.
2024-05-05 15:23:58 +02:00
Stefan Haller
618fe533f8 Add commitPrefix for defining a prefix for any project (#3291)
- **PR Description**

Adds a new option `git.comitPrefix` to act similarly to
`git.commitPrefixes`, except, if defined, it applies to any repo that
doesn't have an entry in `git.commitPrefixes`.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-05-01 19:12:53 +02:00
Jonathan Duck
01ff18dd92 Add commitPrefix for defining a prefix for any project 2024-05-01 19:03:12 +02:00
Stefan Haller
af0897f18f Enable the commit graph in the divergence view (#3537)
- **PR Description**

In the "View divergence from upstream" view we have so far disabled the
commit graph because it was too difficult to implement properly. I
really miss it though, so here's a PR that enables it there, too.

For feature branches it is not essential, because these usually don't
contain merges and the graph is a trivial line. However, for the master
branch against its upstream it is useful too see how many PRs were
merged since you last fetched it, and the graph helps a lot with that.
Also, when we implement #3536 it will be very useful there, too.
2024-04-30 13:53:35 +02:00
Stefan Haller
b7673577a2 Enable the commit graph in the divergence view 2024-04-30 13:50:46 +02:00
Stefan Haller
00c55d5711 chore: fix some comments and typos (#3535)
- **PR Description**
fix some comments and typos
2024-04-28 10:02:59 +02:00
knowmost
0677a58e9f chore: fix some comments and typos
Signed-off-by: knowmost <knowmost@outlook.com>
2024-04-28 09:44:59 +02:00
Stefan Haller
b3a60ce407 Add config options for length of commit hash displayed in commits view (#3505)
- **PR Description**

Add a new config option `gui.commitHashLength` to change the length of
the commit hash displayed in commits view.

default:
<img width="472" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/98684296/36dced1e-0c74-4dbd-8670-98e17a75d83a">

With config:
```yaml
gui:
  commitHashLength: 3
```
<img width="463" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/98684296/e8023cd8-f138-4af8-ae0e-3661f80206ca">


- Changes
- Added the user config option to to `pkg/config/user_config.go` and
`schema/config.json`
  - documented in `docs/Config.md`
- Changed the code that displays the hash in
`pkg/gui/presentation/commits.go`
  
---

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-04-28 08:22:48 +02:00
Stefan Haller
b63321a302 Refactor pkg/gui/presentation/commits.go slightly to be consistent
Change `func displayCommit()` so all the individual strings are built first,
then the whole thing `cols` is put together. Before, most strings were built
prior to constructing `cols`, but a few were built inside the `cols`
construction.
2024-04-27 11:31:19 +02:00
Olivia Bahr
a4354ccdfb Add config option for length of commit hash displayed in commits view
- Add config option `commitHashLength` to to pkg/config/user_config.go
- Changed the hash display in pkg/gui/presentation/commits.go
2024-04-27 11:30:49 +02:00
Stefan Haller
aa81e191e2 Support externalDiffCommand in diffing mode (#3519)
- **PR Description**

Support `git.paging.externalDiffCommand` config in diffing mode (i.e.
when showing the diff between two commits using `W`).

Fixes #3518.
2024-04-25 08:53:14 +02:00
Stefan Haller
496308e023 Support external diff command in diffing mode 2024-04-25 08:50:30 +02:00
Stefan Haller
98c569749f Use git.paging.colorArg in diffing mode diff 2024-04-25 08:50:30 +02:00
Stefan Haller
047380f311 Cleanup: use separate Arg calls for unrelated arguments 2024-04-25 08:50:30 +02:00
Stefan Haller
b2ff09ec0c Use errors.New instead of fmt.Errorf with no parameters (#3523) 2024-04-24 10:53:39 +02:00
ChengenH
dd6bfa1680 chore: use errors.New to replace fmt.Errorf with no parameters. 2024-04-24 16:21:34 +08:00
Stefan Haller
0a5e9b2d60 Drop update-ref todos pointing to head (#3456)
- **PR Description**

The rebase.updateRefs feature of git is very useful to rebase a stack of
branches and keep everything nicely stacked; however, it is usually in
the way when you make a copy of a branch and want to rebase it "away"
from the original branch in some way or other. For example, the original
branch might sit on main, and you want to rebase the copy onto devel to
see if things still compile there. Or you want to do some heavy history
rewriting experiments on the copy, but keep the original branch in case
the experiments fail. Or you want to split a branch in two because it
contains two unrelated sets of changes; so you make a copy, and drop
half of the commits from the copy, then check out the original branch
and drop the other half of the commits from it.

In all these cases, git's updateRefs feature insists on moving the
original branch along with the copy in the first rebase that you make on
the copy. I think this is a bug in git, it should create update-ref
todos only for branches that point into the middle of your branch
(because only then do they form a stack), not when they point at the
head (because then it's a copy). I had a long discussion about this on
the git mailing list [1], but people either don't agree or don't care
enough.

So we fix this on our side: whenever we start a rebase for whatever
reason, be it interactive, non-interactive, or behind-the-scenes, we
drop any update-ref todos that are at the very top of the todo list,
which fixes all the above-mentioned scenarios nicely.

I will admit that there's one scenario where git's behavior is the
desired one, and the fix in this PR makes it worse: when you create a
new branch off of an existing one, with the intention of creating a
stack of branches, but before you make the first commit on the new
branch you realize some problem with the first branch (e.g. a commit
that needs to be reworded or dropped). It this case you do want both
branches to be affected by the change. In my experience this scenario is
much rarer than the other ones that I described above, and it's also
much easier to recover from: just check out the other branch again and
hard-reset it to the rebased one.

[1]
https://public-inbox.org/git/354f9fed-567f-42c8-9da9-148a5e223022@haller-berlin.de/
2024-04-23 08:32:17 +02:00
Stefan Haller
8b99a3c949 Drop update-ref commands at the top of the rebase-todo file
The rebase.updateRefs feature of git is very useful to rebase a stack of
branches and keep everything nicely stacked; however, it is usually in the way
when you make a copy of a branch and want to rebase it "away" from the original
branch in some way or other. For example, the original branch might sit on main,
and you want to rebase the copy onto devel to see if things still compile there.
Or you want to do some heavy history rewriting experiments on the copy, but keep
the original branch in case the experiments fail. Or you want to split a branch
in two because it contains two unrelated sets of changes; so you make a copy,
and drop half of the commits from the copy, then check out the original branch
and drop the other half of the commits from it.

In all these cases, git's updateRefs feature insists on moving the original
branch along with the copy in the first rebase that you make on the copy. I
think this is a bug in git, it should create update-ref todos only for branches
that point into the middle of your branch (because only then do they form a
stack), not when they point at the head (because then it's a copy). I had a long
discussion about this on the git mailing list [1], but people either don't agree
or don't care enough.

So we fix this on our side: whenever we start a rebase for whatever reason, be
it interactive, non-interactive, or behind-the-scenes, we drop any update-ref
todos that are at the very top of the todo list, which fixes all the
above-mentioned scenarios nicely.

I will admit that there's one scenario where git's behavior is the desired one,
and the fix in this PR makes it worse: when you create a new branch off of an
existing one, with the intention of creating a stack of branches, but before you
make the first commit on the new branch you realize some problem with the first
branch (e.g. a commit that needs to be reworded or dropped). It this case you do
want both branches to be affected by the change. In my experience this scenario
is much rarer than the other ones that I described above, and it's also much
easier to recover from: just check out the other branch again and hard-reset it
to the rebased one.

[1]
https://public-inbox.org/git/354f9fed-567f-42c8-9da9-148a5e223022@haller-berlin.de/
2024-04-22 20:59:15 +02:00
Stefan Haller
af6d072cc6 Add tests demonstrating undesired behavior with update-ref todos for copied branches
These tests succeed here, but have comments explaining which bits are undesired.
See next commit for a more detailed explanation why.
2024-04-22 20:59:15 +02:00
Stefan Haller
7270dea48d Switch git-todo-parser from fsmiamoto original repo to stefanhaller's fork
Sometimes it takes a while to get PRs accepted upstream, and this blocks our
progress. Since I'm pretty much the only one making changes there anyway, it
makes sense to point to my fork directly.
2024-04-22 20:59:15 +02:00
Stefan Haller
69153acfdb Remove TODO.* from .gitignore
It was added in 2018 (700f8c7e79), but I don't know for what purpose. It just
took me 15 minutes to figure out why my new file todo.go wasn't added, so I'm
removing this entry as I find it more harmful than helpful.
2024-04-22 20:55:03 +02:00
Stefan Haller
b4fbfd20cb Fix amend to operation not working with non-HEAD merge commit (#3510)
- **PR Description**

Resolves https://github.com/jesseduffield/lazygit/issues/3421

The error is "Expected exactly one original SHA, found 0" but the merge
commit hash (`d6a7a04c626e40071133de26ebe8fdd225caa5c0`) is present in
the rebase TODO file.


![image](https://github.com/jesseduffield/lazygit/assets/13722457/2e6d5fdb-af9f-4eae-9972-8e51a77ba614)

![image](https://github.com/jesseduffield/lazygit/assets/13722457/65dd4b1b-b080-47b0-9079-71c5e0d76cd2)

However, the commit is missed during search because the filter is only
looking for pick commits:
580818e935/pkg/utils/rebase_todo.go (L238)

Checking for merge commits as well fixes the issue.

I believe only pick and merge should be valid here. If already in an
interactive rebase, lazygit only allows amending to the current HEAD
commit. When that happens, this whole interactive rebase logic is
bypassed and lazygit just performs `git commit --amend`:
580818e935/pkg/gui/controllers/local_commits_controller.go (L668)

This is the reason why amending to a HEAD merge commit currently works
whereas non-HEAD does not.
2024-04-22 18:58:55 +02:00
Brandon
ef99e47d09 Fix amend to operation not working with non-HEAD merge commit 2024-04-22 08:48:59 -07:00
Stefan Haller
580818e935 pkg: fix some typos (#3364) 2024-04-20 13:49:43 +02:00
thirdkeyword
1c098ff82a pkg: fix some typos
Signed-off-by: thirdkeyword <fliterdashen@gmail.com>
2024-04-20 13:47:39 +02:00
Stefan Haller
34f8f7293c Simplify error handling (#3502)
- **PR Description**

Simplify and canonicalize error handling across the code base.

Previously it was important to make sure that errors don't bubble up
into gocui, because it would panic there; so we had to show errors in
error panels in the right places (in controller code, usually). This is
error-prone because it's easy to forget (see #3490 for an example);
also, it's not always obvious where in the call chain the error panel
needs to be shown. Most of the time it's in controller code, but we had
plenty of calls to `Error()` in helpers, and I remember that I found
this very confusing when I was new to the code base.

Change this so that you can simply return errors everywhere. The
functions to show an error message manually have been removed for
clarity.

I tried to structure the commits so that you can review them one by one.

Closes #3491.
2024-04-18 10:14:51 +02:00
Stefan Haller
caad553502 Remove ErrorMsg
There is no reason any more for application code to show error messages in a
panel. Just return an error instead.
2024-04-18 10:10:30 +02:00
Stefan Haller
723b92916d Rename Error() to ErrorHandler()
It is now only used as the error handler that is passed to gocui.Gui on
construction; it's not a client-facing API any more. Also, it doesn't have to
handle gocui.ErrQuit, as gocui takes care of that.
2024-04-18 10:10:30 +02:00
Stefan Haller
653994845e Return error from RefreshOptions.Then 2024-04-18 10:10:30 +02:00
Stefan Haller
bbad3a70ce Log errors from refresh instead of showing them in a panel
We are already doing this in other cases in this file.
2024-04-18 10:10:30 +02:00
Stefan Haller
1869fda800 Make OnWorker callback return an error
This lets us get rid of a few more calls to Error(), and it simplifies things
for clients of OnWorker: they can simply return an error from their callback
like we do everywhere else.
2024-04-18 10:10:30 +02:00
Stefan Haller
5396a70661 Clean up error handling of WithWaitingStatus and WithWaitingStatusSync 2024-04-18 10:10:30 +02:00
Stefan Haller
82a3d33ce3 Remove calls to Error()
Now that we have an error handler set, we can simply let them bubble up all the
way to gocui.
2024-04-18 10:10:30 +02:00
Stefan Haller
325800a72e Set ErrorHandler 2024-04-18 10:10:30 +02:00
Stefan Haller
9f8ae76189 Bump gocui
In Gui.onWorker we only make the minimum possible change to get things to
compile after the API-breaking change of the gocui update; we'll make this
cleaner later in this branch.
2024-04-18 10:10:30 +02:00
Stefan Haller
8a77e51576 Remove PopupHandler index and mutex
It doesn't seem to be used.
2024-04-16 10:03:35 +02:00
Jesse Duffield
145795c0b0 README.md: Update Sponsors (#3498)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action
2024-04-16 09:25:11 +10:00
github-actions[bot]
cbe6dd7b2f README.md: Update Sponsors 2024-04-15 23:24:36 +00:00
Jesse Duffield
b6ca9090f4 exclude sponsors PRs from release notes (#3499)
- **PR Description**

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-04-16 09:24:21 +10:00
Jesse Duffield
5d13e3cf76 exclude sponsors PRs from release notes 2024-04-16 09:23:37 +10:00
Jesse Duffield
9e5ceaa1ec sponsors.yml: Create PR instead of trying to push to a protected branch (#3493)
- **PR Description**
Uses [this popular-ish
action](https://github.com/marketplace/actions/create-pull-request) to
create a PR.

> How the action behaves:
> 
> If there are changes (i.e. a diff exists with the checked-out base
branch), the changes will be pushed to a new branch and a pull request
created.
> If there are no changes (i.e. no diff exists with the checked-out base
branch), no pull request will be created and the action exits silently.
> If a pull request already exists it will be updated if necessary.
Local changes in the Actions workspace, or changes on the base branch,
can cause an update. If no update is required the action exits silently.
> If a pull request exists and new changes on the base branch make the
pull request unnecessary (i.e. there is no longer a diff between the
pull request branch and the base), the pull request is automatically
closed. Additionally, if
[delete-branch](https://github.com/marketplace/actions/create-pull-request#delete-branch)
is set to true the branch will be deleted.

Demo Action Run:
https://github.com/SachinVin/lazygit/actions/runs/8675283475
Demo PR: https://github.com/SachinVin/lazygit/pull/2

You also might want to consider changing this action to trigger as a
cron job instead on pushes to master.

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-04-16 09:09:06 +10:00
SachinVin
ba0c00b5d1 sponsors.yml: Create PR instead of trying to push to a protected branch 2024-04-13 22:59:55 +05:30
Stefan Haller
145fb6191c standardize commit hash commit sha (#3398)
Standardise on use of 'commit hash' rather than 'commit SHA'
Close: https://github.com/jesseduffield/lazygit/issues/3208
2024-04-12 08:37:30 +02:00
Stefan Haller
7e14d88dc9 Support both Sha and Hash on commits in custom commands
We achieve this by wrapping the model Commit in a custom struct that provides
both.
2024-04-12 08:33:47 +02:00
Stefan Haller
e6a07b3f03 Add integration test that accesses commit properties in a custom command
Useful as a regression test to check that the following commit doesn't break it.
2024-04-12 08:33:47 +02:00
Shin-JaeHeon
28923fc9d0 improve korean translation 2024-04-12 08:33:47 +02:00
pikomonde
19bef17042 rename sha to hash 10, last remaining sha (hopefully) 2024-04-12 08:33:47 +02:00
pikomonde
170c4ecb8c rename sha to hash 9, case: Sha 2024-04-12 08:33:47 +02:00
pikomonde
de1c495704 rename sha to hash 8, update some log and comment 2024-04-12 08:33:47 +02:00
pikomonde
fccfbf1f63 rename sha to hash 7, language translate 2024-04-12 08:33:47 +02:00
pikomonde
05fb12b1d5 rename sha to hash 6, update short hash 2024-04-12 08:33:47 +02:00
pikomonde
9cf1ca10a2 rename sha to hash 5 2024-04-12 08:33:47 +02:00
pikomonde
dc6863b83d rename sha to hash 4 2024-04-12 08:33:47 +02:00
pikomonde
13af335b37 rename sha to hash 3 2024-04-12 08:33:47 +02:00
pikomonde
92aab21d3a rename sha to hash 2 2024-04-12 08:33:47 +02:00
pikomonde
e6ef1642fa rename sha to hash 2024-04-12 08:33:47 +02:00
pikomonde
84333eebc3 renaming variable to CommitHash 2024-04-12 08:33:47 +02:00
pikomonde
7f6eea2a55 standardize 'Commit Sha' to 'Commit Hash' 2024-04-12 08:31:40 +02:00
Stefan Haller
06624e85d6 Add StatusPanelView config (#3309)
Adds a new config `statusPanelView ` which allows you to select the
default view of the main window: `dashboard` (default),
`allBranchesLog`.
2024-04-10 17:43:36 +02:00
oakio
5616d6a9bc Dynamic copyright year 2024-04-10 17:38:57 +02:00
oakio
5c3aacb4cb UserConfig validation 2024-04-10 17:38:57 +02:00
oakio
2b5c814080 Add StatusPanelView config 2024-04-10 17:38:57 +02:00
Stefan Haller
4ba85608c8 Fix stderr redirection (#3479)
- **PR Description**

Seems that there's a problem in the Stdout/Stderr/Stdin stream vars
assignments,
probably copy-paste issue.

If this is intentional, I suggest adding an explanation on why `Stderr`
-> `Stdout` intentionally to avoid other PRs and confused people around
:)

Thanks!
2024-04-09 09:10:35 +02:00
Emanuele "Lele" Calo
a63c660f28 Fix stderr redirection
Seems that there's a problem in the Stdout/Stderr/Stdin vars
assignments, probably copy-paste issue.
2024-04-09 09:08:14 +02:00
Stefan Haller
fab7ca2b58 Fix issue #3308 (#3478)
- **PR Description**

It seems that setting TERM=dumb breaks compatibility with curses
subprocess in Go, especially with `pinentry-curses`

This fixes #3308
2024-04-09 09:07:44 +02:00
Emanuele "Lele" Calo
7b0e06d885 TERM: remove TERM variable hard-coded value set 2024-04-09 04:15:03 +02:00
Jesse Duffield
426375b7cd Replace min/max helpers with built-in min/max (#3482)
- **PR Description**

We upgraded our minimum Go version to 1.21 in commit
57ac9c2189. We can now replace our
`utils.Min` and `utils.Max` functions with the built-in `min` and `max`.

Reference: https://go.dev/ref/spec#Min_and_max

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [ ] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-04-08 09:31:14 +10:00
Eng Zer Jun
f933a2f7ec Replace min/max helpers with built-in min/max
We upgraded our minimum Go version to 1.21 in commit
57ac9c2189. We can now replace our
`utils.Min` and `utils.Max` functions with the built-in `min` and `max`.

Reference: https://go.dev/ref/spec#Min_and_max
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2024-04-07 23:24:10 +08:00
Stefan Haller
ed61b9a7f2 pkg: fix some comment (#3481) 2024-04-07 11:06:42 +02:00
hongkuang
d8c1eb879b pkg: fix some comment
Signed-off-by: hongkuang <liurenhong@outlook.com>
2024-04-07 16:09:26 +08:00
Stefan Haller
c02408bba0 Add spinner config options (#3463)
- **PR Description**

Add `spinner` config section to the user config. The section has 2
options:
- `frames` - list of strings that are iterated in the spinner animation
- `rate` - spinner's rate in milliseconds

Closes #3435
2024-04-06 13:49:51 +02:00
Artem Belyakov
f3dba743f0 Add SpinnerConfig
This new config section allows to customize frames and rate of
thespinner
2024-04-06 13:46:15 +02:00
Stefan Haller
53f0c4aeff Migrate null keybindings to <disabled>, and remove our yaml fork (#3459)
- **PR Description**

Migrate users' config files to change all `null` keybindings to
`"<disabled>"`. Then remove our yaml fork, since that was the only
reason we were using it.

Fixes #3458.
2024-04-01 11:15:02 +02:00
Stefan Haller
84e82ea8b6 fixup! Introduce a yaml_utils.Walk function 2024-03-30 13:05:33 +01:00
Stefan Haller
8487bc397d Remove our yaml fork
Switch back to the official go-yaml package.
2024-03-29 17:55:06 +01:00
Stefan Haller
93aee0dca0 Migrate null keybindings to "<disabled>"
Unfortunately the migration code requires yaml v3, but our yaml fork is based on
v2, so we need to import both in app_config.go in this commit, which is ugly. We
can clean this up in the next commit.
2024-03-29 17:55:06 +01:00
Stefan Haller
4d8b8b647a Introduce a yaml_utils.Walk function 2024-03-29 17:55:06 +01:00
Stefan Haller
2385c1d111 Make URLs in confirmation panels clickable, and underline them (#3446)
- **PR Description**

This is especially helpful for the breaking changes popup, which has a
link to the release notes, but it could also be useful for other panels
that display some warning or error with a link to more information.
2024-03-29 10:58:55 +01:00
Stefan Haller
5d509efe19 Underline links in confirmation panels 2024-03-29 10:55:33 +01:00
Stefan Haller
b9a75ee0ed Make links clickable in confirmation panels
This is not opt-in, we do it always. I can't imagine a situation where we
wouldn't want it.
2024-03-29 10:55:33 +01:00
Stefan Haller
d102f12304 Make HandleGenericClick a little smarter
Make it recognize URLs wrapped in angle brackets, and followed by punktuation.
We don't need this for the status panel, but we will need it for confirmation
panels.
2024-03-29 10:55:33 +01:00
Stefan Haller
6396d1ce03 Extract a function HandleGenericClick 2024-03-29 10:55:33 +01:00
Stefan Haller
c59e6b6451 Cleanup: don't mess with globals in tests without resetting them
Changing globals in the init() function of a test file is a bad idea, as it
affects all other tests that run after it. Do it explicitly in each test
function that needs it, and take care of restoring the previous value
afterwards.
2024-03-29 10:55:33 +01:00
Stefan Haller
1cedfa463b Fix schema link in Config.md (#3451)
The schema at https://json.schemastore.org/lazygit.json is broken and
doesn't work. It should actually be removed.
2024-03-28 13:31:28 +01:00
Stefan Haller
9b035aed67 Fix schema link in Config.md 2024-03-28 13:24:54 +01:00
Stefan Haller
ce9cdd8d78 Fix rewording signed commits when the log.showsignature git config is true (#3431)
- **PR Description**

For people who have the log.showsignature git config set to true, trying
to reword a signed commit would put the signature verification into the
subject field and the commit subject into the description field of the
commit message panel. Amending commits, adding co-authors to a commit,
and copying a commit message to the clipboard would all be broken in a
similar way.

Slightly related is #1911, but back then it was more about performance
than wrong behavior, it seems.

Fixes #3425.
2024-03-28 13:19:11 +01:00
Stefan Haller
f774b7eb5c Fix rewording signed commits when the log.showsignature git config is true
For people who have the log.showsignature git config set to true, trying to
reword a signed commit would put the signature verification into the subject
field and the commit subject into the description field of the commit message
panel. Amending commits, adding co-authors to a commit, and copying a commit
message to the clipboard would all be broken in a similar way.
2024-03-28 13:16:10 +01:00
Stefan Haller
e4b4b6d5f4 Fix excluding files in submodules or worktrees (#3432)
- **PR Description**

Make the "Add to .git/info/exclude" command work correctly in a worktree
or in a submodule. Previously it would result in an error message.

Fixes #3427.
2024-03-28 13:13:52 +01:00
Stefan Haller
93251db67e Fix the "Add to .git/info/exclude" command in submodules or worktrees 2024-03-28 13:11:08 +01:00
Stefan Haller
de52a68b53 Add a test that demonstrates the problem
Using the "Add to .git/info/exclude" in a worktree results in an error message,
as the test shows. The same would happen in a submodule, but I'm not adding an
extra test for that, as the circumstances are the same.
2024-03-28 13:11:08 +01:00
Stefan Haller
42ebf1947a Cleanup: simplify return statements 2024-03-28 13:11:08 +01:00
Stefan Haller
c995e7ef2e Cleanup: remove pointless condition and error message
The file .git/info/exclude can't possibly show up in the files panel.
2024-03-28 13:11:08 +01:00
Stefan Haller
04fcb78c0c Keep the same commit selected when exiting filtering mode (#3416)
- **PR Description**

When exiting filtering mode, we currently keep the selection index the
same in the commits panel. This doesn't make sense at all, since the
index in the filtered view has no relation to the index in the
unfiltered view.

I often use filtering mode (either by path or by author) to find a given
commit faster than I would otherwise be able to. When exiting filtering
mode, it's useful to keep the same commit selected, so that I can look
at the surrounding commits, see which branch it was a part of, etc. So
reselect the commit again after exiting filtering mode.

Sometimes this is not possible, most likely when the commit is so long
ago that it's outside of the initial 300 range. In that case, at least
select the commit again that was selected before I entered filtering;
this is still better than arbitrarily keeping the same selection index.
2024-03-28 12:27:02 +01:00
Stefan Haller
bd8518355e Keep the same commit selected when exiting filtering mode
When exiting filtering mode, we currently keep the selection index the same in
the commits panel. This doesn't make sense at all, since the index in the
filtered view has no relation to the index in the unfiltered view.

I often use filtering mode (either by path or by author) to find a given commit
faster than I would otherwise be able to. When exiting filtering mode, it's
useful to keep the same commit selected, so that I can look at the surrounding
commits, see which branch it was a part of, etc. So reselect the commit again
after exiting filtering mode.

Sometimes this is not possible, most likely when the commit is so long ago that
it's outside of the initial 300 range. In that case, at least select the commit
again that was selected before I entered filtering; this is still better than
arbitrarily keeping the same selection index.
2024-03-28 12:23:46 +01:00
Stefan Haller
f93cb54b5d Fix crash when filtering the keybindings menu (#3450)
- **PR Description**

It would crash when some keybindings are set to null, and the filter
string is such that only those keybindings remain visible.

Fixes #3449.
2024-03-28 12:19:06 +01:00
Stefan Haller
0b70dfbf46 Fix crash when filtering the keybindings menu
It would crash when some keybindings are set to null, and the filter string is
such that only those keybindings remain visible.

The reason for the crash is that when inserting non-model items (menu section
headers in this case) you specify a column to align them to. This works on the
assumption that the number of columns is always the same. It can cope with the
case that columns are removed because they are empty for all items; but it can't
cope with the case that the getDisplayStrings function returns a lower number of
columns.

And this is what happened here: MenuViewModel.GetDisplayStrings would omit the
keybinding column when none of the entries have a keybinding. This logic is
unnecessary, the generic list rendering mechanism takes care of this, so
removing this logic fixes the crash.

We do have to make sure though that the column is really empty when there's no
keybinding, so change the logic to use FgCyan only when there's a keybinding.
2024-03-28 09:58:45 +01:00
Stefan Haller
38876ba141 Update Busy.md (#3433)
- **PR Description**
enqueing -> enqueueing
2024-03-26 23:12:49 +01:00
Ikko Eltociear Ashimine
57786fbb1f Update Busy.md
enqueing -> enqueueing
2024-03-26 23:08:51 +01:00
Stefan Haller
e295ccefab Fix deleting update ref todos (#3439)
- **PR Description**

Deleting an update-ref todo in an interactive rebase now behaves as
expected (i.e. it leaves the branch referenced by the update-ref
untouched). Previously it would have deleted the branch referenced by
the update-ref todo when the rebase was continued. See #3418 for more
details.

Fixes #3418.
2024-03-26 22:43:46 +01:00
Stefan Haller
1fdcc29277 Fix deleting update-ref todos
It is a bad idea to read a git-rebase-todo file, remove some update-ref todos,
and write it back out behind git's back. This will cause git to actually remove
the branches referenced by those update-ref todos when the rebase is continued.

The reason is that git remembers the refs affected by update-ref todos at the
beginning of the rebase, and remembers information about them in the file
.git/rebase-merge/update-refs. Then, whenever the user performs a "git rebase
--edit-todo" command, it updates that file based on whether update-ref todos
were added or removed by that edit. If we rewrite the git-rebase-todo file
behind git's back, this updating doesn't happen.

Fix this by not updating the git-rebase-todo file directly in this case, but
performing a "git rebase --edit-todo" command where we set ourselves as the
editor and change the file in there. This makes git update the bookkeeping
information properly.

Ideally we would use this method for all cases where we change the
git-rebase-todo file (e.g. moving todos up/down, or changing the type of a
todo); this would be cleaner because we wouldn't mess with git's private
implementation details. I tried this, but unfortunately it isn't fast enough.
Right now, moving a todo up or down takes between 1 and 2ms on my machine;
changing it to do a "git rebase --edit-todo" slows it down to over 100ms, which
is unacceptable.
2024-03-26 22:29:56 +01:00
Stefan Haller
6da9d55e47 Cleanup: update outdated comment
We used to pass the todo string, but this has changed to instructions a while
ago.
2024-03-26 22:25:43 +01:00
Stefan Haller
ba85f93fb3 Extend delete_update_ref_todo test to actually test what it was supposed to
In the test we simply removed the update-ref todo but didn't make any other
changes to the todos. This should really have kept everything the way it was,
including the other branch head. The fact that the star was gone was really
because of the bug that we are going to fix later in the branch.

Change the test so that it also makes a change before the update-ref todo; this
way we test that the star is gone because we deleted the update-ref, not because
of the bug.

To guard against the bug, we add another assertion for the branches view to test
that both branches are still there. This currently fails.
2024-03-26 22:23:50 +01:00
Stefan Haller
cdbec3997d Cleanup: fix typo in test comment 2024-03-26 22:23:50 +01:00
Stefan Haller
fb675b79f8 Set the TERM env variable (#3420)
Resolves #3419

I have tested this change with all the pagers shown in [the
docs](https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md).
Are there others that people frequently use and I should test?

A nice side effect of setting `TERM=dumb` is that `less` now correctly
complains (e.g. when forgetting to set `--paging=never` for delta:


![image](https://github.com/jesseduffield/lazygit/assets/4602612/33e9c048-6ab0-4196-95f6-86ee8effc873)


## Pagers Tested

### none

![image](https://github.com/jesseduffield/lazygit/assets/4602612/4e408fe6-5f19-4142-9183-de56fd738962)

### Delta

![image](https://github.com/jesseduffield/lazygit/assets/4602612/90dd12fa-ed58-4d49-9f71-da5e57f63a74)

```yaml
git:
  paging:
    colorArg: always
    pager: delta --paging=never
```

#### diff-so-fancy

![image](https://github.com/jesseduffield/lazygit/assets/4602612/930e6b93-904e-49a2-bfc2-9b5d9639f514)

```yaml
git:
  paging:
    colorArg: always
    pager: diff-so-fancy
```

#### ydiff

![image](https://github.com/jesseduffield/lazygit/assets/4602612/c2464f0c-f34f-4ebc-9624-8bc0350d92a7)

```yaml
git:
  paging:
    colorArg: always
    pager: ydiff -p cat
```

#### difft

![image](https://github.com/jesseduffield/lazygit/assets/4602612/599dee7a-6568-40e4-9213-76ba643d651f)

```yaml
git:
  paging:
    externalDiffCommand: difft --color=always
```
2024-03-23 23:49:22 +01:00
Tau
f30be824b3 Set the TERM env variable
This communicates to pagers that we're in a very simple
terminal that they should not expect to have much capabilities.

See #3419
2024-03-23 23:46:37 +01:00
Jesse Duffield
e1c3ef6629 Update README.md 2024-03-23 21:01:19 +11:00
Jesse Duffield
a70bb0a7aa Update README.md 2024-03-23 20:59:53 +11:00
Jesse Duffield
7718cb009b Update README.md
Updating for top-level sponsorship stuff
2024-03-23 20:58:02 +11:00
Jesse Duffield
1337a943fe Update interactive rebase demo (#3392)
**PR Description**

This is in anticipation of the new release which supports range-select.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-03-23 20:48:54 +11:00
Stefan Haller
471ea39758 Fix inline status removal when recording demos 2024-03-23 20:45:51 +11:00
Jesse Duffield
c3f0b5cb4a Update interactive rebase demo
I'm adding an explicit delay between moving the commits and selecting
the next items because otherwise it happens too fast
2024-03-23 20:45:51 +11:00
Stefan Haller
3675570a39 Fix container detection (#3412)
- **PR Description**

Running WSL without a container would be treated as native linux,
causing problems at it would then attempt to use `xdg-open`. This was
caused by `isContainer()` always returning true due to some dubious
conditionals. These have been removed.

The env-var check seems to not be used by lazygit, nor any common
containers, and therefore appears to only exist to manually tell lazygit
to behave as if it were inside of a container. This functionality has
been kept, but the env-var has been changed to be all uppercaps as to
comply with the POSIX standard.

Fixes #2757
Bug introduced in 4d78d76
2024-03-22 14:43:31 +01:00
aritmos
68495ea0ee Fix container detection
Running WSL without a container would be treated as native linux, causing problems at it would then attempt to use `xdg-open`.
This was caused by `isContainer()` always returning true due to some dubious conditionals. These have been removed.

The env-var check seems to not be used by lazygit, nor any common containers, and therefore appears to only exist to manually tell lazygit to behave as if it were inside of a container.
This functionality has been kept, but the env-var has been changed to be all uppercaps as to comply with the POSIX standard.

Fixes #2757
Bug introduced in 4d78d76
2024-03-22 13:42:15 +01:00
Stefan Haller
53363b761c Add config to truncate commit hashes when copying them to the clipboard (#3402)
- **PR Description**

I often copy hashes in the commits panel in order to paste them into
Github comments (or other places), and I can't stand it when they have
the full length.

I picked a default of 12 for this; I find this to be a good middle
ground between being reliable in large repos (12 still works in the
linux kernel repo today, but it might not be enough in really huge
repos) and not being too ugly (many smaller repos can probably get away
with less).
2024-03-22 10:01:43 +01:00
Stefan Haller
96c5cbe34e Change CopiedToClipboard text to start lower-case
It is used in the context "'xyz' copied to clipboard", so it looks weird when it
start uppercase.
2024-03-22 09:59:46 +01:00
Stefan Haller
b8a0473c68 Change toast for copying sha to clipboard to include what was copied
This makes it easier to see that "y, enter" copies the full sha, whereas ctrl-o
copies an abbreviated sha.
2024-03-22 09:58:54 +01:00
Stefan Haller
571141ea7c Change log message for copying sha to the clipboard to include "full"
To make it even clearer that this is different from copying a sha with ctrl-o.
2024-03-22 09:58:54 +01:00
Stefan Haller
3b29705a78 Add config to truncate commit hashes when copying them to the clipboard
I often copy hashes in the commits panel in order to paste them into Github
comments (or other places), and I can't stand it when they have the full length.

I picked a default of 12 for this; I find this to be a good middle ground
between being reliable in large repos (12 still works in the linux kernel repo
today, but it might not be enough in really huge repos) and not being too ugly
(many smaller repos can probably get away with less).

We deliberately don't change this for the "Copy to clipboard" menu, since this
gives users a way to copy the unabbreviated sha if they need this occasionally.
2024-03-22 09:58:54 +01:00
Stefan Haller
28dd7f9467 Make it easy to create "amend!" commits (#3409)
- **PR Description**

To support this, we turn the confirmation prompt of the "Create fixup
commit" command into a menu; creating a fixup commit is the first entry,
so that "shift-F, enter" behaves the same as before. But there are
additional entries for creating "amend!" commits, either with or without
file changes. These make it easy to reword commit messages of existing
commits.
2024-03-22 08:32:16 +01:00
Stefan Haller
150cc70698 Make it easy to create "amend!" commits
To support this, we turn the confirmation prompt of the "Create fixup commit"
command into a menu; creating a fixup commit is the first entry, so that
"shift-F, enter" behaves the same as before. But there are additional entries
for creating "amend!" commits, either with or without file changes. These make
it easy to reword commit messages of existing commits.
2024-03-22 08:27:45 +01:00
Stefan Haller
c92e9d9bdc Remove CreateFixupCommitDescription as it's identical to CreateFixupCommit 2024-03-22 08:27:45 +01:00
Stefan Haller
e23337f8f5 Support editing multiple files at once using range selection (#3407)
- **PR Description**

This makes it possible to select a range of files (either in the files
panel, or in the commit-files panel), and hit `e` to open them all at
once in the editor.

We pass all of them to a single editor command, hoping that the editor
will be able to handle multiple files (VS Code and vim do).

We ignore directories that happen to be in the selection range; this
makes it easier to edit multiple files in different folders in tree
view. We show an error if only directories are selected, though.
2024-03-22 08:22:46 +01:00
Stefan Haller
73019574a8 Support editing multiple files at once using range selection
We pass all of them to a single editor command, hoping that the editor will be
able to handle multiple files (VS Code and vim do).

We ignore directories that happen to be in the selection range; this makes it
easier to edit multiple files in different folders in tree view. We show an
error if only directories are selected, though.
2024-03-22 08:20:16 +01:00
Stefan Haller
9b5269b490 When adding a new remote, select it and fetch it (#3401)
- **PR Description**

I'm doing these two things every time I add a new remote, in 100% of the
cases, so do them automatically for me.
2024-03-22 08:19:45 +01:00
Stefan Haller
e8db27b0b3 When creating a new remote, select it and fetch it
I'm doing these two things every time I add a new remote, in 100% of the cases,
so do them automatically for me.
2024-03-22 08:17:12 +01:00
Stefan Haller
337a0dbc9b Make the links in the status panel point to the current version rather than master (#3397)
We've seen a lot of issues recently where people complain that lazygit
doesn't behave as documented, but that was only because they were
running the latest release but were looking at the documentation of
master. Make the documentation links in the status panel point to the
release that they are using in the hope that this will help a little bit
with this problem.
2024-03-22 08:16:20 +01:00
Stefan Haller
5870133924 Make links in status view clickable, and underline them 2024-03-22 08:13:59 +01:00
Stefan Haller
fa79c92748 Make the links in the status panel point to the current version rather than master
We've seen a lot of issues recently where people complain that lazygit doesn't
behave as documented, but that was only because they were running the latest
release but were looking at the documentation of master. Make the documentation
links in the status panel point to the release that they are using in the hope
that this will help a little bit with this problem.
2024-03-22 08:13:59 +01:00
Stefan Haller
251bfb6a24 Always prompt to return from subprocess if there was an error (#3410)
- **PR Description**

When lazygit suspends itself to the background to run an external
command, and the command returns a non-zero exit code, always show the
prompt for pressing enter to return to lazygit, even if the
`promptToReturnFromSubprocess` is set to `false`. The rationale is that
if the process returned an error, it likely also printed some error
message to the console that users will always want to read.

I was considering turning the `promptToReturnFromSubprocess` config into
an enum with values `never`, `onlyOnError`, `always`, but then I felt
that `onlyOnError` is really the only sensible choice for people who
have it set to `false` now, so I just hard-coded that.
2024-03-22 08:13:15 +01:00
stk
377eced31a Always prompt to return from subprocess if there was an error
Except when we are running integration tests, in which case we never want to
prompt because there wouldn't be a way to confirm the prompt.
2024-03-21 14:17:10 +01:00
Stefan Haller
fadc2893d2 Add NixOs installation instructions to README.md (#3249)
Extend README.md with instructions on how to try and install the lazygit
on NixOs.
2024-03-19 12:38:20 +01:00
Radosław Śnieżek
1e59de2768 Add NixOs installation instructions README.md
Extend README.md with instructions on how to try and install
the lazygit on NixOs.
2024-03-19 12:32:13 +01:00
Stefan Haller
1d4448d691 Fixed translations for zh_TW (#3393)
- **PR Description**

Improve translations for Traditional Chinese.
2024-03-19 07:59:59 +01:00
Stefan Haller
2c33f0ce1f Fix indentation 2024-03-19 07:55:23 +01:00
Stefan Haller
14b3e0574c Improve translations for zh_TW
Authored-by: Oliver Tzeng <olivertzeng@proton.me>
2024-03-19 07:55:23 +01:00
Stefan Haller
318a399bfb Fix enabling/disabling of ctrl-o in commit message panel (#3395)
- **PR Description**

This fixes two minor regressions introduced in #3097 related to commands
that open a commit message panel but don't set an onSwitchToEditor
function (an example is the commit message panel that appears when
moving a custom patch to a new commit):
- the "Press <c-o> to open menu" hint was hidden. That's wrong, it is
still possible to open the menu in this case. (And it still worked, we
just wouldn't show the hint.)
- invoking the "open in editor" menu item would silently do nothing. Now
we set a DisabledReason for the item in this case.
2024-03-19 07:13:20 +01:00
Stefan Haller
7764e6d1cb Fix disabling the switch-to-editor menu item if unavailable
Some operations don't support switching to the editor from the commit message
panel; an example is the commit message panel that appears when moving a custom
patch into a new commit. Disable the "open in editor" menu entry in this case,
instead of silently doing nothing.
2024-03-18 21:10:58 +01:00
Stefan Haller
1a9ce9db94 Always show the "Press <c-o> to open menu" help text in the commit panel
Previously we would hide it if no onSwitchToEditor function was set; that was
from a time when <c-o> was bound directly to the switch-to-editor command. Now
it is bound to showing a menu, and that menu is always available even if no
onSwitchToEditor function is set. (We rather need to disable the switch to
editor item _within_ that menu, see next commit.)
2024-03-18 20:44:03 +01:00
Stefan Haller
9a3db0dfbd Update translations for polish language (#3389)
- **PR Description**

Hi, I'm happy using `lazygit` from quite a while. I've decided to give
back to community fraction of my time. I'm native polish speaker, and
seen that polish translation have some gaps.

I've added missing translation for polish language and improved existing
one. I've followed technical jargon used on
https://git-scm.com/book/pl/v2/
 
For easier diff comparison and feature maintenance, I've ordered keys to
be in same order as those in `english.go`
2024-03-17 18:53:13 +01:00
undg
d65b21d6b8 Add missing translations for polish 2024-03-17 18:46:19 +01:00
Stefan Haller
435a835c51 Use substring filtering instead of fuzzy filtering by default (#3376)
By default we now search for substrings; you can search for multiple
substrings by separating them with spaces. Add a config option
`gui.filterMode` that can be set to 'fuzzy' to switch back to the
previous behavior.

Addresses #3373.
2024-03-17 12:28:13 +01:00
Stefan Haller
4f2bebe453 Get rid of the retain-sort-order-when-filtering logic again
For die-hard fuzzy-searching fans it's probably in the way, so taking it out
makes fuzzy filtering work better. For substring filtering it always retains the
sort order anyway.
2024-03-17 12:23:07 +01:00
Stefan Haller
7d2163d632 Rename FuzzySearchFunc to FilterFunc
It isn't necessarily fuzzy any more.
2024-03-17 11:56:29 +01:00
Stefan Haller
561afa9901 Rename FuzzySearch to FilterStrings
It isn't necessarily fuzzy any more.
2024-03-17 11:55:30 +01:00
Stefan Haller
a8797c7261 Default to substring filtering, add option to go back to fuzzy filtering
By default we now search for substrings; you can search for multiple substrings
by separating them with spaces. Add a config option gui.filterMode that can be
set to 'fuzzy' to switch back to the previous behavior.
2024-03-17 11:55:09 +01:00
Stefan Haller
a82e26d11e Don't sort the results of fuzzy.Find
It sorts them already, so it's unnecessary. In the next commit we use this same
code for substring searching too, and in that case we don't want to sort because
sorting is by Score, but we don't even fill in the score for substring
searching.
2024-03-17 07:57:19 +01:00
Stefan Haller
2cf8e7bc5c When checking out a remote branch by name, ask the user how (#3388)
- **PR Description**

When checking out a remote branch by name, ask the user how they want to
check it out; the choices are to create a new local branch that tracks
the remote, or a detached head.

This is an alternative to #3371, and fixes #2312.
2024-03-17 07:56:12 +01:00
Stefan Haller
6932e04708 Refresh after creating local branch, before checking it out
This way we see the local branch immediately when switching to the branches
view, and we see an inline waiting status on it when checking it out.
2024-03-17 07:53:38 +01:00
Stefan Haller
30db7234d9 Show inline waiting status when checking out a local branch 2024-03-17 07:53:38 +01:00
Stefan Haller
0d5c748fe8 Show the same menu when pressing space on a remote branch
The old behavior of showing a prompt to choose a name for the new local branch
is still available via the 'n' keybinding.
2024-03-17 07:53:38 +01:00
Stefan Haller
e42cbf95ae When checking out a remote branch by name, ask the user how
The choices are to create a new local branch that tracks the remote, or a
detached head.
2024-03-17 07:53:38 +01:00
Stefan Haller
0360b82aab Don't ask to force-push if the remote rejected updates (#3387)
Lazygit has two ways to decide whether it needs to ask the user to
force-push:
1. if it knows ahead of time that the push will fail because the branch
has diverged, by looking at the incoming/outgoing information that it
shows as ↑3↓7.
2. by examining the error that comes back when the push has failed.

The second situation should happen only rarely, because lazygit fetches
every minute by default, so the ↑3↓7 information is usually up to date.
It might not be if the user turned off auto-fetch (or increased the
auto-fetch interval). However, in this case it's almost always harmful
to prompt the user to force-push, because we know that the reason for
diverging is that something was pushed to the remote, and we would wipe
it out by force-pushing. In such a situation, the more likely user
action is to pull the remote changes and then push normally again.

So just remove the second prompt, and replace it by a better error
message when we detect that updates were rejected remotely.

A little bit of history archeology reveals that the second prompt was
added at a time where we didn't have the first one yet, so at that time
it made sense to have it; but when the first prompt was added, we should
have removed the second.
2024-03-17 07:42:34 +01:00
Stefan Haller
81b497d186 Don't ask to force-push if the remote rejected updates
Lazygit has two ways to decide whether it needs to ask the user to force-push:
1. if it knows ahead of time that the push will fail because the branch has
diverged, by looking at the incoming/outgoing information that it shows as ↑3↓7.
2. by examining the error that comes back when the push has failed.

The second situation should happen only rarely, because lazygit fetches every
minute by default, so the ↑3↓7 information is usually up to date. It might not
be if the user turned off auto-fetch (or increased the auto-fetch interval).
However, in this case it's almost always harmful to prompt the user to
force-push, because we know that the reason for diverging is that something was
pushed to the remote, and we would wipe it out by force-pushing. In such a
situation, the more likely user action is to pull the remote changes and then
push normally again.

So just remove the second prompt, and replace it by a better error message when
we detect that updates were rejected remotely.

A little bit of history archeology reveals that the second prompt was added at a
time where we didn't have the first one yet, so at that time it made sense to
have it; but when the first prompt was added, we should have removed the second.
2024-03-17 07:38:58 +01:00
Stefan Haller
e9d050c5d5 Allow moving and deleting update-ref todos (#3391)
- **PR Description**

Previously it wasn't possible to move an update-ref entry up or down
using ctrl-j and ctrl-k, or to delete an update-ref entry. For moving, a
work-around was to move the surrounding commits instead, but it's still
nice to be able to do it directly. Deleting is very much necessary
though, since there are situations where git adds the update-ref entries
but they are not wanted; one example is if you want to make a copy of a
branch and rebase to a different place, without the original branch
following it. (There's a long discussion about this
[here](https://public-inbox.org/git/adb7f680-5bfa-6fa5-6d8a-61323fee7f53@haller-berlin.de/).)

Update-ref todos can't be set to "drop" like other todos, because they
have no sha associated with them, so we need to delete them immediately.
We show a confirmation before doing that, because you'd have to abort
the rebase if you do it accidentally.

We allow range selecting normal todos and update-ref todos at the same
time; in that case, we delete all the update-ref todos and set all the
other ones to "drop". Not that this is an absolutely necessary feature,
but it wasn't hard to do.
2024-03-17 07:38:25 +01:00
Stefan Haller
5c56bc7015 Set mode to none when calling SetSelectionRangeAndMode with empty non-sticky range
So far, the only situation where we called SetSelectionRangeAndMode was one
where the range could only get larger (in startInteractiveRebaseWithEdit, in
which case update-ref todos can be inserted by the rebase). However, in the last
commit we introduced a new call site where the range can get smaller, including
being reduced to a single item. Since this is indistinguishable from a single
selection, set the mode to none in this case; without this, hitting escape would
seemingly do nothing because it collapses the empty range selection.
2024-03-16 22:01:13 +01:00
Stefan Haller
0608fc6471 Allow deleting update-ref todos 2024-03-16 22:01:13 +01:00
Stefan Haller
64a1a455d6 Extract a findTodo helper function
We will reuse it in the next commit.
2024-03-16 22:01:03 +01:00
Stefan Haller
bd975a8dcb Allow moving update-ref todos up/down 2024-03-16 22:01:03 +01:00
Stefan Haller
e5fa9e1c4a Store full ref in Name field of update-ref commits
Strip the prefix at presentation time instead. This makes it easier to find
update-ref todos in order to move them up/down, or delete them.
2024-03-16 15:48:34 +01:00
Stefan Haller
e8d84a1f2c Refactor: pass Todo to moveTodoUp/Down instead of Sha and Action
We need this because we want to enable moving update-ref todos, which don't have
a sha.
2024-03-16 15:21:17 +01:00
Stefan Haller
fd18db6ba2 Show "breaking changes" message at startup (#3377)
- **PR Description**

Remember which version of lazygit the user was last running, and show a
list of breaking changes since that version (if any) if the user
upgraded to a newer version.

It's a little unobvious how to test this manually, because we don't show
the popup for developer builds. You'll have to build with something like
`go build -ldflags="-X 'main.version=0.41.0'"` in order to test it.

This is an extremely stripped down version of #3261.
2024-03-12 13:30:19 +01:00
Stefan Haller
36fa25fa6d Handle mouse-wheel scrolling in confirmation panel
This can easily happen for the breaking changes panel when there are many.
2024-03-12 13:27:14 +01:00
Stefan Haller
2f4437591e Show popup message with breaking changes on startup 2024-03-12 13:27:14 +01:00
Stefan Haller
d12ceeb1ec Add Co-Author support to new commits (#3097)
- Adds Co-Author support to commit menu (`<C-o>` by default) 
  - `e` Opens up the commit message in your editor
  - `c` Lets you add a co author to your commit
- Cleans up and amend commit attribute menu related code
2024-03-12 08:40:47 +01:00
Stefan Haller
1ec87364fe Add integration test 2024-03-11 09:19:11 +01:00
Abhishek Keshri
7c687938a5 Add commit menu entry "Add co-author" 2024-03-11 09:18:55 +01:00
Abhishek Keshri
744519de60 Add a commit menu to the commit message panel
And move the "switch to editor" command into this menu. So far this is the only
entry, but we'll add another one in the next commit.
2024-03-11 09:18:40 +01:00
Stefan Haller
b8f4cd0ef6 Extract functions AddCoAuthorToMessage and AddCoAuthorToDescription
In this commit we only need the former; the latter will be reused later in this
branch.
2024-03-11 09:18:40 +01:00
Stefan Haller
287195b5b2 Make test assertion more specific
It's safe to rely on git padding the log messages with exactly four spaces (I
think). This makes the diff of the following commit slightly clearer.
2024-03-11 09:18:40 +01:00
Abhishek Keshri
e1b341e174 Make keybindings for the "Amend attribute" menu configurable 2024-03-11 09:18:40 +01:00
Abhishek Keshri
b1523c3f07 Internationalize the tooltips of the "Amend commit attributes" menu 2024-03-11 09:18:40 +01:00
Abhishek Keshri
c3c5753a35 Add forgotten keybindings to Config.md 2024-03-11 09:18:40 +01:00
Jesse Duffield
272e41929c Update sponsors in readme 2024-03-09 20:48:33 +11:00
Stefan Haller
ac4767bb2a Auto-wrap commit message while typing (#3173)
- **PR Description**

Add new config settings `git.commit.autoWrapCommitMessage` (default
true) and `git.commit.autoWrapWidth` (default 72), which allow automatic
as-you-type wrapping of the commit message body to the specified width.

There are occasional situations where this wrapping is in the way, for
example when you need to have longer lines in the message for some
reason (perhaps because you have a very wide ASCII art picture or
table), and you'll have to resort to switching to the editor in that
case. However, in my experience these cases are quite rare.
2024-03-09 10:06:29 +01:00
Stefan Haller
d1f8c45099 Add integration test 2024-03-09 10:00:44 +01:00
Stefan Haller
41a68f7c4a Remove hard line breaks when rewording commits
... and when recalling a commit message from an old commit by pressing up-arrow.

This is necessary because committing turns our soft line breaks into real ones,
but when rewording we want to turn them back into soft ones again, so that it's
possible to insert words at the beginning of a paragraph and have everything
rewrap nicely.

This is only a best effort; the algorithm only removes those hard line breaks
that can be removed without changing the way the message looks. This works well
when the previous commit message was wrapped at the same width, which for most
users should be the most common case; but if it wasn't, the result is not great.
Specifically, if the old wrap width was smaller, some hard line breaks just
won't be removed; if it was wider though, you'll get an unpleasant comb effect
with alternating long and short lines. In such a case it's best to switch to the
editor and use whatever wrapping features you have there (e.g. alt-Q).
2024-03-09 10:00:44 +01:00
Stefan Haller
944d82028f Replace DOS linefeeds with Unix line feeds when loading a commit message
I have seen some commit messages that contain CRLF instead of just LF; I'm not
sure if these were created by a broken git client, but they exist, so we need to
deal with them. Editing them when rewording a commit sort of works, but is a
little strange; the \r characters are invisble, so you need an extra arrow key
press to skip over them.

In the next commit we are going to add more logic related to line breaks, and it
is getting confused by the \r, so it is becoming more important to fix this. The
easiest fix is to normalize the line endings right after loading.
2024-03-09 10:00:44 +01:00
Stefan Haller
379a6f1922 Save and restore the unwrapped description
When preserving the commit message (when cancelling a commit), and later
restoring it, use the unwrapped description.
2024-03-09 10:00:44 +01:00
Stefan Haller
cede021400 Add config for soft-wrapping the commit message body 2024-03-09 10:00:44 +01:00
Stefan Haller
99ad6005e8 Bump gocui 2024-03-09 10:00:07 +01:00
Stefan Haller
dc9ee186f4 Adjust selection after squashing fixups (#3338)
- **PR Description**

Keep the same commit selected after squashing fixup commits, and after
creating fixup commits.

Edge case: it is now possible to have a range of commits selected when
squashing fixups (by using the "in current branch" version of the
command), and in that case we don't bother preserving the range. It
would be possible, but would require more code, and I don't think it's
worth it, so I'm simply collapsing the range in that case.
2024-03-09 07:58:14 +01:00
Stefan Haller
bb26979420 Keep the same line selected after squashing fixup commits
This uses a bit of a heuristic that is hopefully correct most of the time.
2024-03-09 07:55:22 +01:00
Stefan Haller
c6d20c876e Extract common code to a helper method
This should arguably have been done in b133318b40 already; it's becoming more
important now because we're going to extend the common code with more logic in
the next commit.
2024-03-09 07:55:22 +01:00
Stefan Haller
3e3b902228 Move selection down by one after creating a fixup commit 2024-03-09 07:55:22 +01:00
Stefan Haller
dfb45ba893 Extend squash_fixups_in_current_branch test to check the selection
This shows a problem with the wrong commit being selected after squashing.
2024-03-09 07:55:22 +01:00
Stefan Haller
314efe2539 Add test for creating a fixup commit and squashing fixups
We have such a test already (squash_fixups_above_first_commit.go), but it can't
be used for what we want to check here, because it uses the first commit, and we
can't move down from there. So create a new one that basically does the same
thing, but for a commit in the middle. The focus of this new test is to check
how the selection behaves; as you can see, there is a problem both when creating
a fixup and when squashing fixups. We'll address these separately in the next
commits.
2024-03-09 07:55:22 +01:00
Stefan Haller
bbc680266b Support setting a range of commits to "edit" outside of a rebase (#3370)
- **PR Description**

It is now possible to select a range of commits (while not in a rebase),
and hit "e" to edit them all. This starts a rebase on the bottom-most
commit of the range, and sets all the selected commits to "edit"
(skipping merge commits, because they can't be edited).
2024-03-09 07:46:34 +01:00
Stefan Haller
40232440b7 Support setting a range of commits to "edit" outside of a rebase
It starts a rebase on the bottom-most commit of the range, and sets all the
selected commits to "edit" (skipping merge commits, because they can't be
edited).
2024-03-09 07:43:48 +01:00
Stefan Haller
44f553b609 Show all submodules recursively (#3341)
- **PR Description**

Extend the submodules tab to show not only the top-level submodules, but
also their nested submodules, recursively.

Fixes #3306.
2024-03-07 20:20:42 +01:00
Stefan Haller
3b723282cb Show all submodules recursively 2024-03-07 20:16:28 +01:00
Stefan Haller
db4f12929e Pass entire submodule to UpdateUrl instead of name and path separately
This will make the next commit slightly simpler.
2024-03-07 20:16:28 +01:00
Stefan Haller
ea87912a74 Fix deleting submodule where name and path are different 2024-03-07 20:16:28 +01:00
Stefan Haller
ddcd916301 Add test to check that the git dir for a deleted submodule was removed
The test shows that it actually doesn't work when the submodule name is
different from its path. We'll fix this in the next commit.
2024-03-07 20:16:28 +01:00
Stefan Haller
85a6a42bff Extend submodule tests to use a submodule where name and path are different
In most real-world scenarios, name and path are usually the same. They don't
have to be though, and it's important to make sure we use the right one when
passing arguments to git commands, so change the tests to have different name
and path.
2024-03-07 20:16:28 +01:00
Stefan Haller
ad017459d2 Don't strike out reserved keys in menus (#3365)
It seems to cause more confusion than it helps.

Fixes #2819.
2024-03-07 07:30:08 +01:00
Stefan Haller
cfaf4b29d0 Don't strike out reserved keys in menus
It seems to cause more confusion than it helps.
2024-03-06 18:41:27 +01:00
Stefan Haller
8d9e5d1258 Bump gocui (#3356)
This resolves the regression from the last gocui bump that strikethrough
no longer worked.

Fixes #3355.
2024-03-03 18:46:50 +01:00
Stefan Haller
212ec7e8e5 Bump gocui
This resolves the regression from the last gocui bump that strikethrough no
longer worked.
2024-03-03 18:41:03 +01:00
Stefan Haller
0f14065245 Remove support for old style non-interactive rebase (#3348)
When doing a non-interactive rebase using a version of git earlier than
2.26, or by explicitly calling `git -c rebase.backend=apply rebase`,
lazygit can display the pending todos by parsing the numbered patch
files in `.git/rebase-apply/`. Unfortunately, support for this has been
broken for more than three years because of the change in 682db77401
(the string literal "normal" should have been changed to
REBASE_MODE_NORMAL instead of REBASE_MODE_MERGING).

It's not an important bug since you can only get into this situation by
doing a rebase outside of lazygit, and then only with a pretty old git
version or by using very uncommon git options. So instead of fixing the
bug, just remove the code.
2024-03-02 10:28:37 +01:00
Stefan Haller
eb0f7e3d02 Remove support for old-style non-interactive rebases
When doing a non-interactive rebase using a version of git earlier than 2.26, or
by explicitly calling `git -c rebase.backend=apply rebase`, lazygit can display
the pending todos by parsing the numbered patch files in `.git/rebase-apply/`.
Unfortunately, support for this has been broken for more than three years
because of the change in 682db77401 (the string literal "normal" should have
been changed to REBASE_MODE_NORMAL instead of REBASE_MODE_MERGING).

It's not an important bug since you can only get into this situation by doing a
rebase outside of lazygit, and then only with a pretty old git version or by
using very uncommon git options. So instead of fixing the bug, just remove the
code.
2024-03-02 10:26:15 +01:00
Stefan Haller
e9b04b8cfc Allow more than one argument in git.merging.args config (#3336)
- **PR Description**

Fix a bug where merging would fail with an error message when you try to
put more than one argument in the `git.merging.args` config. This broke
with 25f8b0337e.

Fixes #3334.
2024-03-02 10:24:36 +01:00
Stefan Haller
253a0096f9 Break git.merging.args config into separate arguments on whitespace
This makes it possible again to pass multiple arguments, for example
"--ff-only --autostash". This won't work correctly if you want to use
an argument that contains a space, but it's very unlikely that people
will want to do that, so I think this is good enough.
2024-03-02 10:22:01 +01:00
Stefan Haller
aa81c456bb Add a test that demonstrates a bug with multiple args in git.merging.args config
We are currently passing the whole string as a single argument, which doesn't
work of course.
2024-03-02 10:22:01 +01:00
Stefan Haller
ee5533f9bf Don't show branch head on rebase todos if the rebase.updateRefs config is on (#3340)
- **PR Description**

When doing an interactive rebase of a stack of branches with the
`rebase.updateRefs` git config set to true, you get `update-ref` todos
between the "pick" items. In this situation we would still show the
branch head icon for each pick item that used to be the head of a
branch. This is confusing, especially when you want to move a new commit
to the head of a branch in the middle of the stack. Consider the
following scenario:
<img width="410" alt="image"
src="https://github.com/jesseduffield/lazygit/assets/1225667/438b7157-e51e-48fb-95a9-b67039a7ad30">
Here we have made a new commit at the top of the stack, entered
interactive rebase, and moved the commit down to the head of the second
branch. Now it sits between the commit that shows the branch icon of the
second branch, and the update-ref item for the second branch. This is
super confusing, and it's simply better to not show branch icons for
pick entries. That's what this PR does.

We do show the icons if the `rebase.updateRefs` config is off, because
otherwise there would be no indication of where the branches start and
end. Of course, changing anything in this case will destroy the stack,
so maybe it would be better to hide the icons in this case too to make
this more obvious. I'm unsure about that.
2024-03-02 10:20:23 +01:00
Stefan Haller
416a40b0e6 Don't show branch head on rebase todos if the rebase.updateRefs config is on
The additional branch head icon is more confusing than useful in this situation.
The update-ref entries show very clearly where the branch heads will go when
continuing the rebase; the information where the branch heads used to be before
the rebase is not really needed here, and just makes the display more confusing.

I'm not adding more tests here because the changes to the existing tests
demonstrate the change clearly enough.
2024-03-02 10:17:58 +01:00
Stefan Haller
418b316fab Rename showBranchMarkerForHeadCommit parameter to hasRebaseUpdateRefsConfig
Name it after what it is rather than what it is used for. In the next commit we
will use it for another condition.
2024-03-02 10:17:58 +01:00
Stefan Haller
fd8ce7d779 Add test demonstrating the current (undesired) behavior 2024-03-02 10:17:58 +01:00
Stefan Haller
ed34ddc04d Provide two helix presets, one for "helix" and one for "hx" (#3346)
The helix binary seems to be called "helix" on some distributions (e.g.
Arch), but "hx" on others (e.g. Fedora). Provide presets for both, so
that auto-detection from $EDITOR works.

See
https://github.com/jesseduffield/lazygit/issues/2624#issuecomment-1966509979.
2024-03-02 10:16:58 +01:00
Stefan Haller
581161ac34 Provide two helix presets, one for "helix" and one for "hx"
The helix binary seems to be called "helix" on some distributions (e.g. Arch),
but "hx" on others (e.g. Fedora). Provide presets for both, so that
auto-detection from $EDITOR works.
2024-03-02 10:15:03 +01:00
Stefan Haller
69c9477783 Make ctrl-f available in staging view (#3349)
- **PR Description**

A common workflow for me is to create a fixup commit from only some of
my current changes; to do that, I enter a file, stage a few hunks, and
then want to invoke ctrl-f to find the base commit for these changes.
Currently I need to esc back to the files panel in order to do that;
it's more convenient to be able to do this right from the staging panel.

Labelled as "ignore-for-release" because the ctrl-f feature has only
been added after the last release, so no release notes needed for this
change.
2024-03-02 10:13:55 +01:00
Stefan Haller
98d6504d1d Make ctrl-f available in staging view
A common workflow for me is to create a fixup commit from only some of my
current changes; to do that, I enter a file, stage a few hunks, and then want to
invoke ctrl-f to find the base commit for these changes. Currently I need to esc
back to the files panel in order to do that; it's more convenient to be able to
do this right from the staging panel.
2024-03-02 10:12:03 +01:00
Stefan Haller
afb9980ad9 Fix linter warnings (#3351)
These started to pop up in my editor after I installed an update of
gopls, I think.
2024-03-02 10:11:44 +01:00
Stefan Haller
e3809f3111 Fix linter warnings
These started to pop up in my editor after I installed an update of gopls, I
think. It's unfortunate that we don't see them on CI.
2024-03-02 10:09:32 +01:00
Stefan Haller
fe7d1847b7 Fix display of Chinese characters on Windows (#3352)
Bump our gocui dependency, which in turn bumps tcell to v2.7.1, which
should fix problems with multibyte characters on Windows.

Fixes #2741.
2024-03-02 10:08:55 +01:00
Stefan Haller
ad0394aebe Bump gocui
The main change here is to bump tcell to v2.7.1, which should fix problems with
multibyte characters on Windows.
2024-03-01 14:07:19 +01:00
Stefan Haller
af56065dd6 Add author filtering to commit view (#3302)
- **PR Description**

This PR introduces a new feature to the commit view, allowing users to
filter commits based on the author's name or email address. Similar to
the existing path filtering functionality, accessible through `<c-s>`,
this feature allows users to filter the commit history by the currently
selected commit's author if the commit view is focused, or by typing in
the author's name or email address.

This feature adds an entry to the filtering menu, to provide users with
a familiar and intuitive experience


![filter-by-author](https://github.com/jesseduffield/lazygit/assets/3098462/5b00a716-e432-4204-8568-0e93b1411bc7)

- **Please check if the PR fulfils these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2024-02-21 10:00:49 +01:00
Tristan Déplantes
503422a72e Add author filtering to commit view
This commit introduces a new feature to the commit view, allowing users
to filter commits based on the author's name or email address. Similar
to the existing path filtering functionality, accessible through <c-s>,
this feature allows users to filter the commit history by the currently
selected commit's author if the commit view is focused, or by typing in
the author's name or email address.

This feature adds an entry to the filtering menu, to provide users with
a familiar and intuitive experience
2024-02-21 09:58:09 +01:00
Stefan Haller
329b434915 Change "git reset" default to --mixed (#3264)
Calling "git reset" on the command line (without further arguments)
defaults to --mixed, which is reason enough to make it the default for
us, too.

But I also find myself using --mixed more often than --soft. The main
use case for me is that I made a bunch of WIP commits, and want to turn
them into real commits when I'm done hacking. I select the last commit
before the WIP commits and reset to it, leaving all changes of all those
commits in the working directory. Since I want to start staging things
from there, I prefer those modifications to be unstaged at that point,
which is what --mixed does.
2024-02-21 09:57:31 +01:00
Stefan Haller
9362aede8f Add tooltips for reset menu items 2024-02-21 09:55:04 +01:00
Stefan Haller
dfabe8db70 Change "git reset" default to --mixed
Calling "git reset" on the command line (without further arguments) defaults to
--mixed, which is reason enough to make it the default for us, too.

But I also find myself using --mixed more often than --soft. The main use case
for me is that I made a bunch of WIP commits, and want to turn them into real
commits when I'm done hacking. I select the last commit before the WIP commits
and reset to it, leaving all changes of all those commits in the working
directory. Since I want to start staging things from there, I prefer those
modifications to be unstaged at that point, which is what --mixed does.
2024-02-21 09:55:04 +01:00
Stefan Haller
b0f3bb7a9a Use $XDG_STATE_HOME for state.yml (#2936)
- **PR Description**

fixes #2856, #2794, #818
2024-02-18 15:54:55 +01:00
Stefan Haller
c7c8776371 Update Config.md 2024-02-18 15:52:06 +01:00
Ching Pei Yang
7cef4f4e33 Change log path to state dir 2024-02-18 15:36:56 +01:00
Ching Pei Yang
2c0520bc4b Use $XDG_STATE_DIR for state.yml 2024-02-18 15:36:56 +01:00
Ching Pei Yang
2118ecdf8e Switch to github.com/adrg/xdg 2024-02-18 15:36:56 +01:00
Stefan Haller
4302018437 Fix some problems with patches if git diff was customized with config (e.g. external or noprefix). (#3222)
- **PR Description**

I encountered the problem that I couldn't extract changes into a new
commit because I had difftastic as an external git tool configured.

Add `diff.noprefix=false` config Option and also specify `--no-ext-diff`
when doing the `git diff` after applying a patch.
This fixes #3107.
Though, there might be other config options that can cause problems, but
fixing these common cases should be an improvement nevertheless.
2024-02-18 15:34:09 +01:00
Stefan Haller
236f42879c Add integration test
The test would fail without the fixes in the previous commits; even if
only one of the configs is set.
2024-02-18 15:24:09 +01:00
Stefan Haller
d329c92554 Set diff.noprefix=false for all other diff commands too
This fixes problems with being able to stage things in a custom patch correctly.
2024-02-18 15:22:43 +01:00
Matthias Richerzhagen
afbaf82395 Fix problems with patches if git diff was customized with config. 2024-02-18 15:22:43 +01:00
Stefan Haller
a2ff2e6dd9 Keep sort order when filtering lists sorted by date (#3282)
- **PR Description**

Keep the sort order stable when filtering lists of things sorted by date
(branches, stashes, reflog entries).
2024-02-16 13:57:36 +01:00
Stefan Haller
9f0b4d0000 Don't omit section headers when filtering the keybindings menu 2024-02-16 13:51:15 +01:00
Stefan Haller
649048c336 Optionally keep sort order stable when filtering lists
For some lists it is useful to keep the same sort order when filtering (rather
than sorting by best match like we usually do). Add an optional function to
FilteredList to make this possible, and use it whenever we show lists of things
sorted by date (branches, stashes, reflog entries), as well as menu items
because this allows us to keep the section headers in the keybindings menu,
which is useful for understanding what you are looking at when filtering.
2024-02-16 13:51:15 +01:00
Stefan Haller
57ac9c2189 Bump required go version to 1.21
We'll need this to use the slices.Sort function in the next commit. It would
also be possible to use sort.Ints instead, but it's slower.
2024-02-16 13:51:15 +01:00
Stefan Haller
c4eedec9d5 Fix initial scroll bar size again (#3285)
After #3283 we need to read more lines initially so that the scrollbar
goes to its minimal height of 1 for long diffs. Without this, it would
start with a height of 2 and then become smaller after you scroll down
half the window height.

It does mean that we need to read twice the number of lines initially
(up to the limit of 5000). I think it's worth it, I find the incorrect
initial size confusing.
2024-02-16 13:50:50 +01:00
Stefan Haller
2b9cb3a640 Fix number of lines to read from a task initially for the right scroll bar size
After #3283 we need to read more lines initially so that the scrollbar goes to
its minimal height of 1 for long diffs. Without this, it would start with a
height of 2 and then become smaller after you scroll down half the window
height.
2024-02-16 13:48:27 +01:00
Stefan Haller
1081c45397 Fix order of custom commands history (#3286)
- **PR Description**

Fix order problems when saving custom commands history

This fixes two problems:
- each time the custom commands panel was opened, the history of commands would
  be shown in reversed order compared to last time. (The reason is that
  lo.Reverse modifies the slice in place rather than just returning a new,
  reversed slice.)
- when executing a previous command again (either by typing it in again, or by
  picking it from the history), it should move to the beginning of the history,
  but didn't.

We fix this by storing the history in reversed order (as the user sees it in
the panel), this makes the logic simpler. We just have to prepend rather
than append newly added commands now.

While this is theoretically a breaking change, it's not worth bothering because
the order was wrong for existing users in 50% of the cases anyway.
2024-02-16 13:46:04 +01:00
Stefan Haller
6c6201ab04 Fix order problems when saving custom commands history
This fixes two problems:
- each time the custom commands panel was opened, the history of commands would
  be shown in reversed order compared to last time. (The reason is that
  lo.Reverse modifies the slice in place rather than just returning a new,
  reversed slice.)
- when executing a previous command again (either by typing it in again, or by
  picking it from the history), it should move to the beginning of the history,
  but didn't.

We fix this by storing the history in reversed order (as the user sees it in
the panel), this makes the logic simpler. We just have to prepend rather
than append newly added commands now.

While this is theoretically a breaking change, it's not worth bothering because
the order was wrong for existing users in 50% of the cases anyway.
2024-02-16 13:31:37 +01:00
Stefan Haller
ea42275f06 Simplify saving app state 2024-02-16 13:31:37 +01:00
Stefan Haller
5b567f3774 Migrate git.log.showGraph and git.log.order to app state (#3197) 2024-02-16 13:29:24 +01:00
Stefan Haller
7f4a05debf Redraw commits view when showGraph setting changes 2024-02-16 13:23:35 +01:00
Alex March
e354a9bb48 Deprecate git.log.showGraph and git.log.order config
Added identical properties to AppState that should eventually have their defaults set.
2024-02-16 13:23:35 +01:00
Stefan Haller
b01bad7fad Fix two problems related to update-ref rebase todo items (#3290)
- **PR Description**

This fixes two loosely related problems with `update-ref` todos:
1. Panic when hitting enter on an `update-ref` item
2. When selecting an `update-ref` item and then triggering a refresh,
there was a bogus error message `fatal: ambiguous argument '': unknown
revision or path not in the working tree.`
2024-02-16 13:10:05 +01:00
Stefan Haller
3b7f32db95 Avoid crash when hitting enter on an update-ref todo 2024-02-16 13:06:24 +01:00
Stefan Haller
d3804d313c Fix a problem with refreshing while an update-ref todo is selected
Scenario:
- show the files of a commit, escape out of it again
- start an interactive rebase of a stack of branches, with the rebase.updateRefs
  git config set to true
- select one of the update-ref todos
- trigger a refresh (either manually or by bringing lazygit's terminal window to
  the front)

This results in an error message "fatal: ambiguous argument '': unknown revision
or path not in the working tree."

Fix this by putting another band-aid on the check for the commit files refresh.

This is the easiest way to fix the problem, but I don't think it's the best one.
We shouldn't be refreshing the commit files context at all if it isn't visible,
because it's pointless; there's no way to switch to it again except by calling
viewFiles again with a specific ref. But I'm too lazy too figure out how to do
that right now.
2024-02-16 13:01:04 +01:00
Jesse Duffield
8746c3d9e0 Support range select removing files from a commit (#3276)
- **PR Description**
Support adding range select for removing multiple files from a commit.
Closes #3260.

The approaches I saw were to either modify
`RebaseCommands.DiscardOldFileChanges` to accept multiple files or do
the file removals as part of the custom patch workflow. I ended up going
with the second way, but I'd be happy to re-implement with the first
approach if that's preferred.

I added a test that handles several different situations when removing
commit files, and updated the original test for removing a single file
from a commit.

I changed how the user gets informed when removing files from a commit.
The previous version had 2 prompts that I combined into 1 (because those
two situations are now possible to see at the same time), and I added
the total number of files that will be affected. This feature seems like
it could cause some real damage if used improperly, so I'm trying to let
the user know as much as possible.

There are 2 or 3 i18n strings that I removed because they're no longer
used. `RebaseCommands.DiscardOldFileChanges` isn't used anywhere any
more, but I left it in there anyway.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-02-16 21:15:32 +11:00
Aaron Hoffman
c431698dba Fix range select bug
After discarding file changes from the commit, the was still referencing
these indexes as being part of the range select. The consequence was
needing to hit escape twice to exit commit files in some situations.
Canceling the range select after discarding changes fixes that.
2024-02-13 09:10:15 -06:00
Aaron Hoffman
d138f7ce86 Clean up test case
I'm combining the delete single file case from `discard_old_file_change`
with the content of `discard_range_select` and calling that
`discard_old_file_changes`. Hopefully that cleans things up a little
bit.

This also adds a check that the custom patch is getting reset properly.
2024-02-13 09:10:15 -06:00
Aaron Hoffman
62a0c895b4 Cleanup
The waiting status shouldn't happen until after the user has responded
to the popup.

Since we're not giving a standalone prompt about clearing the patch, all
of the business in `discard` doesn't need to be in a function any more
2024-02-13 09:10:15 -06:00
Aaron Hoffman
15d5261933 Support range select removing files from a commit 2024-02-13 09:10:15 -06:00
Stefan Haller
beb730a9e6 Change default of git.log.showGraph to 'always' (#3314)
Change default of git.log.showGraph to 'always'; most people seem to
prefer it to be on.

Fixes #3312.
2024-02-13 14:41:01 +01:00
Stefan Haller
b1d05b6371 Change default of git.log.showGraph to 'always'
Most people seem to prefer it to be on.
2024-02-13 14:34:40 +01:00
Stefan Haller
0c5212ae0b Disallow cherry-picking merge commits (#3316)
Cherry-picking merge commits is currently not supported because of the
way copy/pasting is currently implemented. Disable the command with a
proper error message if the user tries to copy a merge commit, instead
of running into the confusing error message that git would otherwise
give, see #1374.

While we're at it, disable it also when trying to copy an "update-ref"
todo, which doesn't make sense.
2024-02-12 12:03:23 +01:00
Stefan Haller
bc6616d511 Disallow cherry-picking merge commits 2024-02-10 11:27:28 +01:00
Stefan Haller
2c82b3f8dd Disallow cherry-picking update-ref todos 2024-02-10 11:27:28 +01:00
Stefan Haller
dc40fb5267 Cleanup: remove unused method 2024-02-10 11:05:09 +01:00
Stefan Haller
49df908dd3 Fix cherrypick demo (#3287)
Cherrypick selections are now cleared after pasting (#3240), so the demo
needs a tiny change to reflect that.

- **PR Description**
The cherry pick demo is failing after the changes in #3240. This is just
a small update to that demo to reflect the new (and more convenient)
behavior from #3240.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-30 17:10:10 +01:00
Aaron Hoffman
fdc54b7455 Fix cherrypick demo
Cherrypick selections are now cleared after pasting (#3240), so the demo
needs a tiny change to reflect that.
2024-01-30 09:27:44 -06:00
Stefan Haller
607034a61e Clear cherry-picked commits after pasting (#3240)
It can be tedious after each cherry-pick opearation to clear the
selection by pressing escape in order for lazygit to stop displaying
info about copied commits. Also, it seems to be a rare case to
cherry-pick commits to more than one destination.

The simplest solution to address this issue is to clear the selection
upon paste, including merge conflict scenario.
Previously discussed in #3198.
2024-01-30 08:59:38 +01:00
molejnik88
ee173ff7c9 Clear cherry-picked commits after pasting
It can be tedious after each cherry-pick opearation to clear the
selection by pressing escape in order for lazygit to stop displaying
info about copied commits. Also, it seems to be a rare case to
cherry-pick commits to more than one destination.

The simplest solution to address this issue is to clear the selection
upon paste.

The only exception is a merge conflict. Initially, I wanted to clear
selected commits in this scenario too. During a discussion we found out
that it may be convenient to have the copied commits still around.
Aborting the rebase and pasting the commits in the middle of a branch
can be a valid use case.
2024-01-30 09:21:12 +11:00
Jesse Duffield
761c77f5a2 Use slimmer scrollbars (#3283)
(hopefully) fixes https://github.com/jesseduffield/lazygit/issues/1924

The previous scrollbars were too chunky and encroached too much on a
view's content.

The new ones are slim and right-aligned so they encroach into dead space
between views which is much better.

Before:

![image](https://github.com/jesseduffield/lazygit/assets/8456633/fe125804-0cb8-4f9b-be4c-5710fd73ac14)


After:

![image](https://github.com/jesseduffield/lazygit/assets/8456633/8ae18f96-e2fd-46ff-be9a-09e745da1177)

Admittedly, the original scrollbars look more like typical scrollbars
and do a better job at telling you where the start and end of the
scrollbar is. We experimented with having special characters for
scrollbar bounds in the slim version but it all looked pretty ugly, and
there's just not many ascii characters to choose from.

Based on gocui PR: https://github.com/jesseduffield/gocui/pull/45

The important changes are in 
vendor/github.com/jesseduffield/gocui/gui.go
vendor/github.com/jesseduffield/gocui/scrollbar.go

The other changes are just modules being updated.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-30 08:49:36 +11:00
Jesse Duffield
f9e8428061 Use slimmer scrollbars
The previous scrollbars were too chunky and encroached too much on a view's content.

The new ones are slim and right-aligned so they encroach into dead space between views
which is much better
2024-01-30 08:44:03 +11:00
Stefan Haller
9d840088ac Add command to squash all fixups in the current branch (#3274)
Add command to squash all fixups in the current branch.

To do that, change the "Apply fixup commits" command to show a menu with
the two choices "in current branch" and "above the selected commit"; we
make "in current branch" the default, as it's the more useful one most
of the time, even though it is a breaking change for those who are used
to "shift-S enter" meaning "squash above selected".

Fixes #3263.
2024-01-29 10:05:40 +01:00
Stefan Haller
b133318b40 Add command to squash all fixups in the current branch
To do that, change the "Apply fixup commits" command to show a menu with the two
choices "in current branch" and "above the selected commit"; we make "in current
branch" the default, as it's the more useful one most of the time, even though
it is a breaking change for those who are used to "shift-S enter" meaning
"squash above selected".
2024-01-29 09:37:47 +01:00
Stefan Haller
24e79a057c Fix refreshing custom patch view when adding first file to custom patch (#3266)
Fixes #3258.
2024-01-28 10:01:49 +01:00
Stefan Haller
c66667c8c1 Fix main view refresh after adding the first file to a custom patch
This broke with 240948b.
2024-01-28 09:49:56 +01:00
Stefan Haller
e8e7ddea45 Fix typo 2024-01-28 09:49:56 +01:00
Jesse Duffield
6322944a5e Support selecting file range in patch builder (#3259)
- **PR Description**
Adds support for selecting a range of files and adding them to a custom
patch. Closes #3251
The behavior for node selection is the same as used in #3248 because I
copied the approach. Please let me know if there's a mismatch or if
something else is preferred.

I also copied `normalisedSelectedNodes` and
`isDescendentOfSelectedNodes` verbatim, just adapted their signature
types.

It seems like we could share those two functions between
`[]*filetree.CommitFileNode` and `[]*filetree.FileNode` by making those
functions like `func normalisedSelectedCommitNodes[T any](selectedNodes
[]*filetree.Node[T]) []*filetree.Node[T]`. That would require calling
them with a `lo.Map(...)` which returns `node.GetRaw()`, and I feel
weird about giving a different type back to the calling function.

I added a couple of test cases, and all of the existing patch tests pass
for me, but please do let me know if there are any other test cases I
should add.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-28 12:13:42 +11:00
Aaron Hoffman
510f9a1ae1 Support selecting file range in patch builder
test: add move_range_to_index

test: add toggle_range
2024-01-28 12:00:47 +11:00
Jesse Duffield
9b2a5f636a Warn users when attempting to cherry pick with old key (#3271)
I wrote this feature and even I sometimes use the wrong key so I want to
make this very clear to users so that there's no confusion.

We can get rid of this once users have had time to adjust


![image](https://github.com/jesseduffield/lazygit/assets/8456633/8a453eaf-381d-468e-8280-58516eead43a)


- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-28 12:00:03 +11:00
Jesse Duffield
e1aa68a7bd Warn users when attempting to cherry pick with old key
I wrote this feature and even I sometimes use the wrong key so I want
to make this very clear to users so that there's no confusion
2024-01-28 11:48:21 +11:00
Jesse Duffield
cf5d4d4f8e Show better keybinding suggestions (#3203)
- **PR Description**

This PR's goal is to improve discoverability of keybindings in lazygit.
I've have a couple people in real life mention to me that it wasn't
obvious what key to press for viewing rebase options, for example.


This PR:
* shows more keybindings in the options view
* shows certain keybindings prominently in certain modes e.g. 'view
rebase options: m' when mid-rebase.

Before:

![image](https://github.com/jesseduffield/lazygit/assets/8456633/483477ef-93e1-4fd1-af86-3ffa84167f62)


After:

![image](https://github.com/jesseduffield/lazygit/assets/8456633/4c93dd19-f072-45ec-afa6-810727211f66)




- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-28 09:27:01 +11:00
Jesse Duffield
bd7fabef1f Reduce the chance of race condition with list cursor
Before this commit, we had pkg/integration/tests/submodule/add.go
failing with a panic. I'm pretty sure the issue is this: we're now
calling quite a few GetDisabledReason calls on each layout() call,
and if a background thread happens to update a model slice while
we're doing this, we can end up with a selection index that's now
out of bounds because it hasn't been clamped to match the new list
length.

Specifically, here we had the selected index being -1 (the list starts
empty and somehow the value is -1 in this case) and then the list
gets a new submodule so the length is now 1, but the list cursor
doesn't know about this so remains on the old value. Then we confirm
the length is greater than zero and try to get the selected submodule
and get an out of bounds error.

This commit fixes the issue by clamping the selected index whenever
we get the length of the list so that it stays in-sync. This is not
a perfect solution because the length can change at any time, but
it seems to reliably fix the test, and using mutexes didn't seem to
make a difference.

Note that we're swapping the order of IFileTree and IListCursor in
the file tree view model to ensure that the list cursor's Len()
method is called (which performs the clamping).

Also, comment from the PR:
This 'trait' pattern we're using is convenient but can lead to awkward
situations. In this case we have both the list view model and the
(embedded) list cursor with a Len() method. The list cursor Len()
method just calls the list view model Len() method. But I wanted
to make it that the list view model now calls ClampSelection() on the
list cursor whenever it obtains the length. This will cause an
infinite loop because ClampSelection() internally calls Len()
(which calls the list view model's Len() method which in turn
calls ClampSelection() again, etc).

The only reason we were passing the list view model into the list
cursor was to supply the length method, so now we're just doing
that directly, and letting the list view model delegate the Len()
call to the list cursor, which now itself calls ClampSelection.
2024-01-28 09:20:52 +11:00
Jesse Duffield
1a38d515d7 Display more keybindings on-screen 2024-01-28 08:33:13 +11:00
Jesse Duffield
0f9d9e13d1 Show mode-specific keybinding suggestions
As part of making lazygit more discoverable, there are certain keys which you almost certainly
need to press when you're in a given mode e.g. 'v' to paste commits when cherry-picking. This
commit prominently shows these keybinding suggestions alongside the others in the option view.

I'm using the same colours for these keybindings as is associated with the mode elsewhere e.g.
yellow for rebasing and cyan for cherry-picking. The cherry-picking one is a bit weird because
we also use cyan text to show loaders and app status at the bottom left so it may be confusing,
but I haven't personally found it awkward from having tested it out myself.

Previously we would render these options whenever a new context was activated, but now that we
need to re-render options whenever a mode changes, I'm instead rendering them on each screen
re-render (i.e. in the layout function). Given how cheap it is to render this text, I think
it's fine performance-wise.
2024-01-28 08:33:13 +11:00
Jesse Duffield
c07b3fad64 Ensure file view length is never returned as -1
This was causing issues when obtaining selected items
2024-01-28 08:33:13 +11:00
Jesse Duffield
9bf3063457 Add loads of tooltips (#3269)
- **PR Description**

This is cherry-picked from
https://github.com/jesseduffield/lazygit/pull/3203. That PR both adds
tooltips and adds keybinding suggestions, and the latter part is having
some concurrency issues that I want to properly fix before merging.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-28 08:20:51 +11:00
Jesse Duffield
7bddf53223 Improve keybinding descriptions
This adds a bunch of tooltips to keybindings and updates some keybinding descriptions (i.e. labels).

It's in preparation for displaying more keybindings on-screen (in the bottom right of the screen),
and so due in part to laziness it shortens some descriptions so that we don't need to manage both
a short and long description (for on-screen vs in-menu). Nonetheless I've added a ShortDescription
field for when we do want to have both a short and long description.

You'll notice that some keybindings I deemed unworthy of the options view have longer descriptions,
because I could get away with it.
2024-01-28 08:12:01 +11:00
Jesse Duffield
0aa6109d4d Render keybinding cheatsheet as markdown table
We're going to be adding tooltips to the cheatsheet to better explain what each actions
does. As such, we're switching to a table format rather than a list.

I'm also changing how the keys are represented, using a markdown approach rather than
an html approach
2024-01-28 08:12:01 +11:00
Stefan Haller
cb1b13e95e Keep same selection range when quick-starting an interactive rebase (#3247)
This is useful if you want to move a range of commits, so you select
them, and then realize it's better to do it in an interactive rebase. Pressing 'i'
preserves the range now.
2024-01-26 11:26:00 +01:00
Stefan Haller
f9876c9742 Keep same selection range when quick-starting an interactive rebase
This is useful if you want to move a range of commits, so you select them, and
then realize it's better to do it in an interactive rebase. Pressing 'i'
preserves the range now.
2024-01-26 11:18:13 +01:00
Stefan Haller
d28a2ec059 Add tests for preserving the selection when pressing 'i'
Preserving the selection for a non-range selection already works as expected;
however, the test for a selection range shows an undesired behavior.
2024-01-26 11:18:06 +01:00
Stefan Haller
f226a277bf Rename MinMax to SortRange 2024-01-26 11:18:06 +01:00
Jesse Duffield
cce29209be Add shortcuts for filtering files by status (#3137)
- 's' for showing only staged files
- 'u' for showing only unstaged files
- 'r' for resetting the filter

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->

I've thought about adding `disabled` reasons for them but they kinda
don't make sense since if there are only `unstaged` files, disabling the
`Show only staged files` makes no sense because the `Show only unstaged
files` shows nothing different so we should disable that too, and then
what's the point of having a menu if everything except for `reset` is
disabled.
2024-01-26 20:57:12 +11:00
Luka Markušić
efb6524fa0 Add shortcuts for filtering files by status
- 's' for showing only staged files
- 'u' for showing only unstaged files
- 'r' for resetting the filter
2024-01-26 20:53:16 +11:00
Stefan Haller
a65f003ccc Inline status for fetching remotes (#3238)
When fetching a remote in the remotes tab, show the status inline (i.e.
in the list row of the remote), like we do when fast-forwarding a branch
in the branches panel.
2024-01-26 08:48:05 +01:00
Stefan Haller
b485363006 Remove unused text FetchingRemoteStatus
We just removed the last use of it.
2024-01-26 08:29:04 +01:00
Stefan Haller
7fb5266027 Use inline status for fetching remotes 2024-01-26 08:29:04 +01:00
Stefan Haller
ae89dde969 Pass absolute file paths to all editor commands (#3255)
- **PR Description**

This helps work around bugs in editors that may get confused about
relative paths (like nvim-remote, see
https://github.com/neovim/neovim/issues/18519), and shouldn't have any
negative effect on others.
2024-01-26 08:26:54 +01:00
Stefan Haller
12500be554 Pass absolute file paths to all editor commands
This helps work around bugs in editors that may get confused about relative
paths (like nvim-remote, see https://github.com/neovim/neovim/issues/18519), and
shouldn't have any negative effect on others.
2024-01-25 08:56:10 +01:00
Jesse Duffield
05b97c8c8e Support range select for staging/discarding files (#3248) 2024-01-25 18:26:24 +11:00
Jesse Duffield
0402674ee7 Fix error message for selected lines
We had the actual and expected lines swapped around erroneously
2024-01-25 11:34:59 +11:00
Jesse Duffield
269ef7f250 Support range select for staging/discarding files
As part of this, you must now press enter on a merge conflict file
to focus the merge view; you can no longer press space and if you do
it will raise an error.
2024-01-25 11:34:59 +11:00
Jesse Duffield
798225d9e1 Move file discard action into files controller
It's better just having all the keybindings in one file especially when you want to
share code
2024-01-24 20:51:00 +11:00
Stefan Haller
b7d4db2446 Use git rev-parse to obtain repository and worktree paths (#3183)
- **PR Description**
This changes GetRepoPaths() to pull information from `git rev-parse`
instead of partially reimplementing git's logic for pathfinding. This
change fixes issues with bare repos, esp. versioned homedir use cases,
by aligning lazygit's path handling to what git itself does. I believe
it also paves the way for lazygit to run from any subdirectory of a
working tree with relatively minor changes.

Addresses #1294 and #3175.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-24 08:47:49 +01:00
John Whitley
3d9f1e02e5 Refactor repo_paths.go to use git rev-parse
This changes GetRepoPaths() to pull information from `git rev-parse`
instead of effectively reimplementing git's logic for pathfinding. This
change fixes issues with bare repos, esp. versioned homedir use cases,
by aligning lazygit's path handling to what git itself does.

This change also enables lazygit to run from arbitrary subdirectories of
a repository, including correct handling of symlinks, including "deep"
symlinks into a repo, worktree, a repo's submodules, etc.

Integration tests are now resilient against unintended side effects from
the host's environment variables. Of necessity, $PATH and $TERM are the
only env vars allowed through now.
2024-01-24 08:40:01 +01:00
Stefan Haller
74d937881e Make range selections created with the mouse non-sticky (#3234)
- **PR Description**

I prefer this because I almost never use sticky range selections, but
I'm not sure everybody agrees. Also, this fixes the issue that just
clicking a line in a diff (without dragging) already creates a range
selection. It still does, technically, but it's no longer a problem
because a non-sticky one-line range selection behaves the same as a
non-range selection.

See #3233.
2024-01-24 08:26:33 +01:00
Stefan Haller
e72c759541 Make range selections created with the mouse non-sticky
I prefer this because I almost never use sticky range selections. Also, this
fixes the issue that just clicking a line in a diff (without dragging) already
creates a range selection. It still does, technically, but it's no longer a
problem because a non-sticky one-line range selection behaves the same as a
non-range selection.
2024-01-24 08:22:55 +01:00
README-bot
9cd69e46df Updated README.md 2024-01-23 22:28:37 +00:00
Jesse Duffield
5511cc170e Support range select for rebase actions (#3232)
- **PR Description**

Adds support for range select in rebase actions both mid-rebase and
outside a rebase i.e.:
* pick
* drop
* fixup
* squash
* move up
* move down

Also includes a refactor to support a withItems wrapper for keybinding
handlers that support a range of items to be selected.

TODO:
* [x] Add integration tests
* [x] Add some LogAction calls (some are currently commented out)

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-24 09:28:22 +11:00
Jesse Duffield
41d5f4dbb5 Disallow updating non-standard TODO lines when rebasing 2024-01-23 17:23:56 +11:00
Jesse Duffield
f0de880136 Support range select in rebase actions 2024-01-23 17:23:56 +11:00
Jesse Duffield
44e2542e4a Better assertion logic for line selection
Previously if we marked a line with IsSelected() we would check if it was selected, but
we would not check if other lines were unexpectedly selected. Now, if you use IsSelected(),
we ensure that _only_ the lines you marked as such are the selected lines.
2024-01-23 13:43:39 +11:00
Jesse Duffield
a5f3515ad8 Set groundwork for better disabled reasons with range select
Something dumb that we're currently doing is expecting list items
to define an ID method which returns a string. We use that when copying
items to clipboard with ctrl+o and when getting a ref name for diffing.

This commit gets us a little deeper into that hole by explicitly requiring
list items to implement that method so that we can easily use the new
helper functions in list_controller_trait.go.

In future we need to just remove the whole ID thing entirely but I'm too
lazy to do that right now.
2024-01-23 13:03:37 +11:00
Stefan Haller
a67ad44781 Add config setting to suppress showing file icons (#3216)
- **PR Description**

Add a config option `gui.showFileIcons` (default: true) which can be set
to false to suppress showing file icons.
2024-01-22 08:43:54 +01:00
Stefan Haller
36134006c5 Add config setting to suppress showing file icons 2024-01-22 08:40:03 +01:00
README-bot
3215839524 Updated README.md 2024-01-22 02:40:34 +00:00
Jesse Duffield
c2218133bc Show file names in default colour (#3081)
Fixes https://github.com/jesseduffield/lazygit/issues/3077

Show unstaged file names in default colour

Previously, we had the following rules:
* file names were in red when unstaged or partially staged
* directory names were in red if unstaged, yellow if partially staged,
and
  green if fully staged

Red text on a black background can be hard to read, so instead I'm
changing it
so that unstaged files have their names in the default text colour.
I'm also making it so that partially staged files are in yellow, just
like how
partially staged directories are yellow (same deal with the commit files
view
when adding to a custom patch).

So the new rules are:
* unstaged files/directories use the default colour
* partially staged files/directories are in yellow
* fully staged files/directories are in green

I've also done a refactor on the code clean up some dead code from when
the file tree
outline was drawn with box characters, and I've made it so that the
indentation in
each line is handled inside the function that draws the line rather than
in the recursive
parent function. This makes it easier to experiment with things like
showing the file
status characters on the left edge of the view (admittedly after
experimenting with it,
I decided I didn't like it). Apologies for having a refactor and a
functional change
in the one commit but by the time I was done, I couldn't be bothered
going back and
retroactively splitting it into two halves.
2024-01-22 13:40:19 +11:00
Jesse Duffield
7c3d8921b7 Show unstaged file names in default colour
Previously, we had the following rules:
* file names were in red when unstaged or partially staged
* directory names were in red if unstaged, yellow if partially staged, and
  green if fully staged

Red text on a black background can be hard to read, so instead I'm changing it
so that unstaged files have their names in the default text colour.
I'm also making it so that partially staged files are in yellow, just like how
partially staged directories are yellow (same deal with the commit files view
when adding to a custom patch).

So the new rules are:
* unstaged files/directories use the default colour
* partially staged files/directories are in yellow
* fully staged files/directories are in green

I've also done a refactor on the code clean up some dead code from when the file tree
outline was drawn with box characters, and I've made it so that the indentation in
each line is handled inside the function that draws the line rather than in the recursive
parent function. This makes it easier to experiment with things like showing the file
status characters on the left edge of the view (admittedly after experimenting with it,
I decided I didn't like it). Apologies for having a refactor and a functional change
in the one commit but by the time I was done, I couldn't be bothered going back and
retroactively splitting it into two halves.
2024-01-22 13:31:05 +11:00
Stefan Haller
221ebdc1fb Keep same branch selected when fetching a branch while sorted by date (#3186)
- **PR Description**

Now that branches can be sorted by date, there's a new situation that we
didn't have before: when fetching a branch, its committer date can
change, so it will move up in the list; we need to update the selection
index to follow. This is important for the case that master is behind
its upstream and you want to rebase your checked-out branch onto master:
in that case you would select master, press "f" to fetch, and then press
"r" to rebase onto it. It's very bad if master doesn't stay selected
after fetching.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] 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))
* [ ] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-19 09:31:21 +01:00
Stefan Haller
2c9b4770bc Keep same branch selected when refreshing branches
This wasn't necessary before, because the only available branch sorting option
was by recency, so the sort order couldn't change except by checking out
branches. Now, you can sort by committer date, so the branch order can change by
fetching; in this case it's important to keep the same branch selected. One
important use case is to rebase the checked-out branch onto master; you select
master, press "f" to fetch it (this can now change its position in the list),
and then press "r" to rebase. To make this work smoothly it's important to keep
master selected after pressing "f".
2024-01-19 09:25:07 +01:00
Stefan Haller
9867180202 Add test showing how branch should stay selected after fetching (but doesn't yet) 2024-01-19 09:23:55 +01:00
README-bot
8dec35ba67 Updated README.md 2024-01-18 23:56:30 +00:00
Jesse Duffield
74e07080d0 Add range selection ability on list contexts (#3207)
- **PR Description**

Issue: https://github.com/jesseduffield/lazygit/issues/3196

This PR adds the ability to select a range of items in list contexts. It
does this in two ways:
* Sticky range select: like what we already have in the staging view,
you press 'v' to toggle range select and then use up/down keys to extend
the range
* Non-sticky range select: rather than explicitly toggling this on/off,
you use shift+up/down to extend the range

The PR adds the ability to range select in all list contexts, but it's
up to individual actions to opt-in to supporting a range. This PR only
supports it for copying a range of commits for cherry-picking. We can
add more support iteratively so that we're not merging a single giant
PR. For all actions requiring selection of a single-item, an error will
be shown if a range is selected.

Other use cases we want to support in the near future:
* marking commits as pick/drop/fixup/squash/etc when mid-rebase
* fixup/squash/drop when outside rebase
* moving commits up/down (in or out of rebase)
* staging/unstaging multiple files
* discarding multiple files

## Updated keybindings

Because the 'v' binding is now globally dedicated to toggling range
select, I've changed the cherry-pick copy/paste keys from 'c' and 'v' to
'shift+C' and 'shift+V' respectively. I've also nullified the 'v'
keybinding on the 'view divergence from upstream' option in the upstream
options menu (conveniently it was the first option in the menu so you
can press enter on it).

## Standardised range select display

As a bonus, this PR standardises how we display a range select. We
already had range select support in the patch explorer view and merge
conflicts view, but they were directly rendering the highlighted
selection (i.e. blue background colour) in the content written to the
view, rather than tell the view which lines were selected and have the
view highlight them itself. A convenient benefit here is that now the
entire line is highlighted, including trailing space, rather than just
the content of the line. Another convenient benefit is that our
integration tests can now easily ask the view which lines are selected,
rather than depending on the specific context, because the view keeps
track of it.

I've removed the selectedRangeBgColor config option because
selectedLineBgColor should be fine. I don't see the need for two
options, but tell me if you think otherwise.

Also, another thing we're standardising on: hitting escape will cancel
the range select, which in the staging/patch-building views means if
you're selecting a range, you'll need to hit escape twice to exit out of
the view. For consistency, we're also applying this logic if you have a
hunk selected. I personally would much prefer this and have several
times accidentally exited out of the view when trying to cancel a range
select by pressing escape. In lazygit in general, 'escape' means 'exit
out of the innermost mode' and I would consider range select to be a
kind of mode.

## Sticky vs non-sticky range interaction

Here's the state machine that explains how the sticky and non-sticky
range select modes interact. Although users will typically pick one or
the other, it's important to be clear on what the logic is if you swap
between them:
```
(no range, press 'v') -> sticky range
(no range, press arrow) -> no range
(no range, press shift+arrow) -> nonsticky range
(sticky range, press 'v') -> no range
(sticky range, press arrow) -> sticky range
(sticky range, press shift+arrow) -> nonsticky range
(nonsticky range, press 'v') -> no range
(nonsticky range, press arrow) -> no range
(nonsticky range, press shift+arrow) -> nonsticky range
```

Also if you press escape in either range mode, it cancels the range
select.

## Some implementation details
* when the action involves toggling e.g. toggling cherry-pick copy or
toggling staged, we decide what to do based on the selection: for
example with staging: if there are any unstaged changes in the
selection, we'll stage everything, otherwise we unstage everything. This
is the logic we already had when staging individual directories.
* we retain range selection if a view loses focus
* where we previously set SetSelectedLineIdx all over the place (e.g.
setting selected line idx to 0 when checking out a branch) we're now
using SetSelection which also resets the range select. There are only a
couple of places where we would still want to use SetSelectedLineIdx
(e.g. when the user moves up/down a page, because they would want to
retain range select in that case)

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-19 10:56:16 +11:00
Jesse Duffield
ab3004bcd5 Show unacknowledged toast message upon integration test failure
Often if a test fails and there's an unaknowledged toast message, that message will
explain why the test failed. Given that we don't display toast messages in
integration tests when they run (for reasons I can't recall right now), we need to
log it as part of the error message.
2024-01-19 10:50:49 +11:00
Jesse Duffield
1ea0c270df Disable range-select in menu and suggestions view
We don't need it there so no need to enable it.

I'm leaving the disabled reason checks there, even though they're now redundant,
because they're only one-liners and they communicate intent.
2024-01-19 10:50:49 +11:00
Jesse Duffield
51fb82d6bf Enforce single-item selection in various actions
We want to show an error when the user tries to invoke an action that expects only
a single item to be selected.

We're using the GetDisabledReason field to enforce this (as well as DisabledReason
on menu items).

I've created a ListControllerTrait to store some shared convenience functions for this.
2024-01-19 10:50:49 +11:00
Jesse Duffield
280b4d60f8 Support select range for cherry pick
This requires us to change the 'v' keybinding for paste to something else,
now that 'v' is used globally for toggling range select. So I'm using
'shift+v' and I'm likewise changing 'c' to 'shift+c' for copying, so
that they're consistent.

We will need to clearly communicate this change in keybindings.
2024-01-19 10:50:49 +11:00
Jesse Duffield
54bd94ad24 Add SetSelection function for list contexts and use it in most places
The only time we should call SetSelectedLineIdx is when we are happy for a
select range to be retained which means things like moving the selected line
index to top top/bottom or up/down a page as the user navigates.

But in every other case we should now call SetSelection because that will
set the selected index and cancel the range which is almost always what we
want.
2024-01-19 10:47:21 +11:00
Jesse Duffield
8840c1a2b7 Remove 'v' menu keys
We can no longer use this because 'v' is globally reserved for range select.
Conveniently it was the first item in the menu anyway for both of these.
2024-01-19 10:47:21 +11:00
Jesse Duffield
d08fafb1c4 Clear range select upon pressing 'escape'
This is the highest priority of the escape actions because it's the thing you're
most likely to want to do upon hitting escape if you have a range selected.

Applying this to the staging/patch-building views is tricky: if we want this logic
for when a range of lines is selected, we'll also need to apply it when a hunk
is selected too. I still think it's worth it though: I've often accidentally
escaped from the staging view when trying to cancel a range selection.
2024-01-19 10:47:21 +11:00
Jesse Duffield
f3eb180f75 Standardise display of range selection across views
We're not fully standardising here: different contexts can store their range state however
they like. What we are standardising on is that now the view is always responsible for
highlighting the selected lines, meaning the context/controller needs to tell the view
where the range start is.

Two convenient benefits from this change:
1) we no longer need bespoke code in integration tests for asserting on selected lines because
we can just ask the view
2) line selection in staging/patch-building/merge-conflicts views now look the same as in
list views i.e. the highlight applies to the whole line (including trailing space)

I also noticed a bug with merge conflicts not rendering the selection on focus though I suspect
it wasn't a bug with any real consequences when the view wasn't displaying the selection.

I'm going to scrap the selectedRangeBgColor config and just let it use the single line
background color. Hopefully nobody cares, but there's really no need for an extra config.
2024-01-19 10:47:21 +11:00
Jesse Duffield
c0c3aac02e Support non-sticky range selection in patch explorer views 2024-01-19 10:47:21 +11:00
Jesse Duffield
24a4302c52 Add range selection ability on list contexts
This adds range select ability in two ways:
1) Sticky: like what we already have with the staging view i.e. press v then use arrow keys
2) Non-sticky: where you just use shift+up/down to expand the range

The state machine works like this:
(no range, press 'v') -> sticky range
(no range, press arrow) -> no range
(no range, press shift+arrow) -> nonsticky range
(sticky range, press 'v') -> no range
(sticky range, press arrow) -> sticky range
(sticky range, press shift+arrow) -> nonsticky range
(nonsticky range, press 'v') -> no range
(nonsticky range, press arrow) -> no range
(nonsticky range, press shift+arrow) -> nonsticky range
2024-01-19 10:47:21 +11:00
Jesse Duffield
e887a2eb3c Stop hiding debug vscode launch tasks
No idea why these were hidden in the first place
2024-01-19 10:47:21 +11:00
README-bot
8a94663df1 Updated README.md 2024-01-16 12:24:57 +00:00
Jesse Duffield
8062f96d6b Fix CI erroneously marking failed tests as successful (#3221)
CI is erroneously saying that our integration tests are passing.

As @stefanhaller says in a comment:
> It broke with this commit:
aaecd6cc40.
Since that change, the run_integration_tests.sh script will exit with
the exit status of the the last mv command, not the test run. Should be
pretty easy to fix.

Thanks to Stefan for fixing this

(The reason I'm saying this all here in the PR description is that PR
descriptions now get included in merge commits)
2024-01-16 23:24:39 +11:00
Stefan Haller
cf59b40a1b Fix exit code of run_integration_tests.sh when capturing code coverage data 2024-01-16 18:23:53 +11:00
Stefan Haller
53acbc8f18 Fix crash with short branch names (#3219) 2024-01-15 13:28:36 +01:00
Stefan Haller
36e57d16bd Don't try to shorten branch names that are already 3 characters or less
This fixes a potential crash when the available width is very small and the
branch name is one to three characters long.
2024-01-15 13:27:49 +01:00
Jesse Duffield
080aa78266 Do not include keybindings from another view in keybindings menu (#3220)
Previously we included all navigation keybindings from all views in the
keybindings menu, meaning if you pressed enter on 'next page' in the
commits view, you'd end up triggering the action in the sub-commits
view.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] 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)
* [x] 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
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-15 20:17:33 +11:00
Jesse Duffield
fc8998e377 Do not include keybindings from another view in keybindings menu
Previously we included all navigation keybindings from all views in the keybindings menu, meaning
if you pressed enter on 'next page' in the commits view, you'd end up triggering the action
in the sub-commits view.
2024-01-15 20:08:11 +11:00
README-bot
d4a0ca35c7 Updated README.md 2024-01-15 03:45:52 +00:00
Jesse Duffield
f79305090b Show Toast instead of error panel when invoking a disabled command (#3180)
- **PR Description**

Addresses #3116.

I'm not 100% sure I like the behavior, but I put it out there so that
others can test it and form an opinion. It not only affects keybindings,
but also invoking menu items (either with enter or with their key
binding): the menu now stays open in that case, which I think is
actually better.

There's a horrible hack for keeping the integration tests working, I
don't have a good idea how to fix that for real. Suggestions welcome.
2024-01-15 14:45:39 +11:00
Stefan Haller
f133224683 Double the duration of error toasts
This gives users more time to read them.
2024-01-14 17:45:35 +01:00
Stefan Haller
83337d9fa8 Allow showing Disabled errors as error panel instead of toast 2024-01-14 17:45:35 +01:00
Stefan Haller
84e1d15079 Make DisabledReason a struct
This is a pure refactoring, no change in behavior yet. We'll add another field
to the struct in the next commit.
2024-01-14 17:45:35 +01:00
Stefan Haller
09a24ee97d Use ErrorToast instead of error panel when invoking a disabled command 2024-01-14 17:45:35 +01:00
Stefan Haller
99a3ccde71 Add ErrorToast function 2024-01-14 17:45:35 +01:00
Stefan Haller
8ca8a43968 Make it mandatory to acknowledge toasts in tests 2024-01-14 17:42:03 +01:00
Stefan Haller
9fa43394fe Make it possible to handle toasts in integration tests
Use it in two selected tests to demonstrate what it looks like.
2024-01-14 17:42:03 +01:00
Jesse Duffield
37590a495c Add 'Quick start interactive rebase' action (#3213)
- **PR Description**

A common issue I have is that I want to move a commit from the top of my
branch all the way down to the first commit on the branch. To do that, I
need to navigate down to the first commit on my branch, press 'e' to
start an interactive rebase, then navigate back up to the top of the
branch, then move my commit back down to the base. This is annoying.

Similarly annoying is moving the commit one-by-one without explicitly
starting an interactive rebase, because then each individual step is its
own rebase which takes a while in aggregate.

This PR allows you to press 'i' from the commits view to start an
interactive rebase from an 'appropriate' base. By appropriate, we mean
that we want to start from the HEAD and stop when we reach the first
merge commit or commit on the main branch. This may end up including
more commits than you need, but it doesn't make a difference.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-13 22:39:06 +11:00
Jesse Duffield
ee106f9af8 Do not perform IO work when getting disabled reason with local commits
Because we obtain disabled reasons after every action, we need to keep the code for doing so
super fast. As such, we should not be hitting the filesystem to get rebase state, instead
we should just get the cached state.

I feel like we should actually be using the cached state everywhere like we do with all
our other models if only for the sake of consistency.
2024-01-13 12:57:49 +11:00
Jesse Duffield
23a98937b4 Update README to add backticks to key
Missed a spot when I originally wrote this
2024-01-13 12:57:49 +11:00
Jesse Duffield
a0b63090e0 Update codebase guide
I'm adding a couple more terms: Keybinding and Action, to keep things standardised
2024-01-13 12:57:49 +11:00
Jesse Duffield
53a8bd2e3f Add ability to start an interactive rebase onto an appropriate base
A common issue I have is that I want to move a commit from the top of my branch
all the way down to the first commit on the branch. To do that, I need to navigate
down to the first commit on my branch, press 'e' to start an interactive rebase,
then navigate back up to the top of the branch, then move my commit back down to
the base. This is annoying.

Similarly annoying is moving the commit one-by-one without explicitly starting
an interactive rebase, because then each individual step is its own rebase which
takes a while in aggregate.

This PR allows you to press 'i' from the commits view to start an interactive
rebase from an 'appropriate' base. By appropriate, we mean that we want to start
from the HEAD and stop when we reach the first merge commit or commit on the main
branch. This may end up including more commits than you need, but it doesn't make
a difference.
2024-01-13 12:57:49 +11:00
Jesse Duffield
e9962b98a7 Set working directory in lazygit test command (#3215)
We need to fetch our list of tests both outside of our test binary and
within. We need to get the list from within so that we can run the code
that drives the test and runs assertions. To get the list of tests we
need to know where the root of the lazygit repo is, given that the tests
live in files under that root.

So far, we've used this GetLazyRootDirectory() function for that, but it
assumes that we're not in a test directory (it just looks for the first
.git dir it can find). Because we didn't want to properly fix this
before, we've been setting the working directory of the test command to
the lazygit root, and using the --path CLI arg to override it when the
test itself ran. This was a terrible hack.

Now, we're passing the lazygit root directory as an env var to the
integration test, so that we can set the working directory to the actual
path of the test repo; removing the need to use the --path arg.

- **PR Description**

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-12 23:33:26 +11:00
Jesse Duffield
a1ce6029c1 Pass -f as single arg in integration test
For some bizarre reason `pkg/integration/tests/filter_by_path/cli_arg.go` is failing as of 8c716184 like so:

```
test_lazygit

  Usage:
    test_lazygit [git-arg]

  Positional Variables:
    git-arg   Panel to focus upon opening lazygit. Accepted values (based on git terminology): status, branch, log, stash. Ignored if --filter arg is passed.
  Flags:
    -h --help               Displays help with available flag, subcommand, and positional value parameters.
    -p --path               Path of git repo. (equivalent to --work-tree=<path> --git-dir=<path>/.git/)
    -f --filter             Path to filter on in `git log -- <path>`. When in filter mode, the commits, reflog, and stash are filtered based on the given path, and some operations are restricted
    -v --version            Print the current version
    -d --debug              Run in debug mode with logging (see --logs flag below). Use the LOG_LEVEL env var to set the log level (debug/info/warn/error) (default: false)
    -l --logs               Tail lazygit logs (intended to be used when `lazygit --debug` is called in a separate terminal tab)
    -c --config             Print the default config
    -cd --print-config-dir   Print the config directory
    -ucd --use-config-dir     override default config directory with provided directory
    -w --work-tree          equivalent of the --work-tree git argument
    -g --git-dir            equivalent of the --git-dir git argument
    -ucf --use-config-file    Comma separated list to custom config file(s)

Unknown arguments supplied:  filterFile
```

where the CLI args are:
```
([]string) (len=5 cap=5) {
 (string) (len=25) "/tmp/lazygit/test_lazygit",
 (string) (len=6) "-debug",
 (string) (len=108) "--use-config-dir=/Users/jesseduffieldduffield/repos/lazygit/test/_results/filter_by_path/cli_arg/used_config",
 (string) (len=2) "-f",
 (string) (len=10) "filterFile"
}
```

This appears to be a bug in flaggy itself. I've updated to the latest version but it still breaks. Bizarrely it works fine on CI and
only fails locally. Running lazygit locally with `lg -f pkg/gui/controllers/helpers/refresh_helper.go` it works fine. So I don't
know what's going on there. At any rate, I'm just going to get the test passing by passing `-f=filterFile` as a single argument.
2024-01-12 20:19:50 +11:00
Jesse Duffield
8c716184c1 Set working directory in lazygit test command
We need to fetch our list of tests both outside of our test binary and within. We need
to get the list from within so that we can run the code that drives the test and runs
assertions. To get the list of tests we need to know where the root of the lazygit repo
is, given that the tests live in files under that root.

So far, we've used this GetLazyRootDirectory() function for that, but it assumes that
we're not in a test directory (it just looks for the first .git dir it can find). Because
we didn't want to properly fix this before, we've been setting the working directory of
the test command to the lazygit root, and using the --path CLI arg to override it when
the test itself ran. This was a terrible hack.

Now, we're passing the lazygit root directory as an env var to the integration test, so
that we can set the working directory to the actual path of the test repo; removing the
need to use the --path arg.
2024-01-12 19:59:31 +11:00
Jesse Duffield
5c888a0b47 Update codebase guide
fixes a line that used an incorrect path
2024-01-11 09:57:05 +11:00
Jesse Duffield
498092a8ec Add codebase guide (#3206)
- **PR Description**

After reading through some AI-generated lazygit docs, it occurred to me
that we should actually be documenting some of this stuff ourselves.

Contributors can feel free to add stuff to this guide if they think it
provides useful context.

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-11 09:50:51 +11:00
Jesse Duffield
caf6a3629d Add codebase guide 2024-01-11 09:43:38 +11:00
Stefan Haller
1ca96bbe5b Fix keybindings for characters involving AltGr on Windows (#3194) 2024-01-10 09:42:30 +01:00
Stefan Haller
cb5d0bca1c Bump gocui
... and switch back from stefanhaller's tcell fork to the official tcell. This
basically reverts 7ccb871a45.
2024-01-10 09:39:25 +01:00
Stefan Haller
ef3d6f4a32 Support insteadOf URL rewriting when opening URLs in browser (#3177) 2024-01-10 09:29:26 +01:00
Stefan Haller
b470442a46 Obtain remote URL by calling "ls-remote --get-url" instead of using git config
This has the advantage that it still works when the user has configured aliases
using the insteadOf feature [1].

[1] https://git-scm.com/docs/git-config/2.42.0#Documentation/git-config.txt-urlltbasegtinsteadOf)
2024-01-10 09:24:23 +01:00
Stefan Haller
bf01c0b00e Allow multiple fetch commands (or fetch and pull) to run concurrently (#3202) 2024-01-10 09:23:22 +01:00
Stefan Haller
76e39af76f Allow multiple fetch commands (or fetch and pull) to run concurrently
Git has a bug [1] whereby running multiple fetch commands at the same time
causes all of them to append their information to the .git/FETCH_HEAD file,
causing the next git pull that wants to use the information to become confused,
and show an error like "Cannot rebase onto multiple branches". This error would
occur when pressing "f" and "p" in quick succession in the files panel, but also
when pressing "p" while a background fetch happens to be running. One likely
situation for this is pressing "p" right after startup.

Since lazygit never uses the information written to .git/FETCH_HEAD, it's best
to avoid writing to it, which fixes the scenarios described above.

However, it doesn't fix the problem of repeatedly pressing "f" quickly on the
checked-out branch; since we call "git pull" in that case, the above fix doesn't
help there. We'll address this separately in another PR.

[1] See https://public-inbox.org/git/xmqqy1daffk8.fsf@gitster.g/ for more
information.
2024-01-10 09:18:38 +01:00
Stefan Haller
5b91cd0cc8 Extract a function fetchCommandBuilder 2024-01-10 09:18:38 +01:00
Stefan Haller
6255728e63 Add a method GitVersion.IsAtLeast 2024-01-10 09:18:38 +01:00
README-bot
b657fc4f0b Updated README.md 2024-01-10 08:17:42 +00:00
Stefan Haller
d294d51791 Add command to find base commit for creating a fixup (#3105) 2024-01-10 09:17:29 +01:00
Stefan Haller
b35f8776e1 Warn when there are hunks with only added lines
The algorithm works by blaming the deleted lines, so if a hunk contains only
added lines, we can only hope that it also belongs in the same commit. Warn the
user about this.

Note: the warning might be overly agressive, we'll have to see if this is
annoying. The reason is that it depends on the diff context size whether added
lines go into their own hunk or are grouped together with other added or deleted
lines into one hunk. However, our algorithm uses a diff context size of 0,
because that makes it easiest to parse the diff; this results in hunks having
only added lines more often than what the user sees. For example, moving a line
of code down by two lines will likely result in a single hunk for the user, but
in two hunks for our algorithm. On the other hand, being this strict makes the
warning consistent. We could consider using the user's diff context size in the
algorithm, but then it would depend on the current context size whether the
warning appears, which could be confusing. Plus, it would make the algorithm
quite a bit more complicated.
2024-01-10 09:11:40 +01:00
Stefan Haller
8ca78412ac Add command to find base commit for creating a fixup 2024-01-10 09:11:40 +01:00
Stefan Haller
33f933ba21 Add config setting for splitting window vertically in half screen mode (#3133) 2024-01-09 15:53:32 +01:00
Stefan Haller
d70dd5123d Add config setting for side panel location (left or top) in half screen mode 2024-01-09 15:45:26 +01:00
Stefan Haller
15da702140 Fix preserving the commit message when description contains blank lines (#3170) 2024-01-09 14:35:43 +01:00
Stefan Haller
cd50c79ae4 Preserve the commit message correctly even if the description has blank lines
There are two possible fixes for this bug, and they differ in behavior when
rewording a commit. The one I chose here always splits at the first line feed,
which means that for an improperly formatted commit message such as this one:

   This is a very long multi-line subject,
   which you shouldn't really use in git.

   And this is the body (we call it "description" in lazygit).

we split after the first line instead of after the first paragraph. This is
arguably not what the original author meant, but splitting after the first
paragraph doesn't really work well in lazygit, because we would try to put both
lines into the one-line subject field of the message panel, and you'd only see
the second and not even know that there are more.

The other potential fix would have been to join subject and description with two
line feeds instead of one in JoinCommitMessageAndDescription; this would have
fixed our bug in the same way, but would result in splitting the above message
after the second line instead of the first. I think that's worse, so I decided
for the first fix.

While we're at it, simplify the code a little bit; strings.Cut is documented to
return (s, "") when the separator is not found, so there's no need to do this on
our side.

We do have to trim spaces on the description now, to support the regular reword
case where subject and body are separated by a blank line.
2024-01-09 14:31:53 +01:00
Stefan Haller
3ebba5f32c Add test demonstrating a bug with preserving the commit message
SplitCommitMessageAndDescription splits at the first '\n\n' that it finds (if
there is one), which in this case is between the two paragraphs of the
description. This is wrong.
2024-01-09 14:31:53 +01:00
Stefan Haller
9a423c388d Remove unused function
I think this is a left-over from before we had the new commit message panel. It
no longer makes sense to add a newline to the commit subject.
2024-01-09 14:31:53 +01:00
Stefan Haller
daf9b8cfa9 Simplify GetCommitMessage
Use git log instead of git rev-list, this way we don't get a line "commit <sha>"
at the beginning that we then have to discard again.

The test TestGetCommitMsg is becoming a bit pointless now, since it just
compares that input and output are identical.
2024-01-09 14:31:53 +01:00
README-bot
b6a9220343 Updated README.md 2024-01-09 13:30:54 +00:00
Stefan Haller
aeb017e029 Add command to open git difftool (#3156) 2024-01-09 14:29:26 +01:00
Stefan Haller
a6174271aa Update cheat sheets and json schema 2024-01-09 14:27:33 +01:00
Stefan Haller
517e0f8248 Add command to open git difftool 2024-01-09 14:27:33 +01:00
Stefan Haller
c1cb95db6f Remove unused function 2024-01-09 14:24:14 +01:00
Stefan Haller
966e5f5337 Fix checking out a tag when there is a branch with the same name (#3179) 2024-01-09 14:23:08 +01:00
Stefan Haller
f244ec8251 Fix checking out a tag when a branch with the same name exists 2024-01-09 14:18:35 +01:00
Stefan Haller
2b97f0fb43 Add test demonstrating the problem
When there's a branch with the same name as the tag, the branch gets checked out
instead of the tag.
2024-01-09 14:18:35 +01:00
Stefan Haller
af5e25cfb5 Replace copy commit SHA with copy commit subject on the y s keybind in the commits view (#3188) 2024-01-09 14:17:05 +01:00
README-bot
93cae68e94 Updated README.md 2024-01-09 09:55:08 +00:00
Jesse Duffield
6e6fe6a489 Show a friendly error message when starting lazygit from a non-existent cwd (#3192)
Closes #3187

- **PR Description**

#3187 observes that lazygit crashes with a stack trace if it's run from
a non-existent current working directory. The steps to reproduce are:

```
mkdir test
cd test
rm -r ../test
lazygit
```

(Note: I can repro this on Ubuntu, but not on macOS Sonoma, where
lazygit starts regardless of whether the current working directory
exists or not.)

Here's how the repro steps look on Ubuntu with this PR applied:

```
simon@ubuntu:/Users/simon/src/3p/lazygit$ go build .
simon@ubuntu:/Users/simon/src/3p/lazygit$ mkdir deleteme
simon@ubuntu:/Users/simon/src/3p/lazygit$ cd deleteme/
simon@ubuntu:/Users/simon/src/3p/lazygit/deleteme$ rm -r ../deleteme
simon@ubuntu:/Users/simon/src/3p/lazygit/deleteme$ ../lazygit
2024/01/02 18:40:15 Error: the current working directory does not exist
```

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
2024-01-09 20:54:50 +11:00
Karim Khaleel
2c2436574d Replace copy SHA with copy subject on commit 'y s' 2024-01-03 02:19:39 +03:00
Simon Whitaker
0cdca9ac2c Update error message 2024-01-02 18:43:39 +00:00
Simon Whitaker
4172be6bc8 Show a friendly error message when starting lazygit from a non-existent cwd
Closes 3187
2024-01-02 18:25:28 +00:00
Stefan Haller
d97b37a178 Add local branch sorting menu (#3182) 2023-12-27 15:30:25 +01:00
Alex March
21334fa889 Add integration test for local branch sort order 2023-12-27 15:25:29 +01:00
Alex March
36a29f225b Add a sort order menu for local branches 2023-12-27 15:25:29 +01:00
README-bot
1e85c4379f Updated README.md 2023-12-27 10:24:12 +00:00
Stefan Haller
470632b97a Add age to stash entries (#3174) 2023-12-27 11:23:57 +01:00
AzraelSec
50044dd5e0 chore: use null char as a stash entries divider during loading 2023-12-27 11:21:49 +01:00
AzraelSec
bc330b8ff3 feat: add age on stash lines 2023-12-27 11:21:49 +01:00
README-bot
7f36494eb2 Updated README.md 2023-12-22 08:16:48 +00:00
Stefan Haller
85c48ba887 Add remote branch sorting menu, saving the option to state.yml (#3171) 2023-12-22 09:16:34 +01:00
Stefan Haller
1e3935cbaf Add integration test for remote branch sort order 2023-12-22 16:30:20 +09:00
Alex March
3fe491fcb2 Implement a sort order menu for remote branches 2023-12-22 16:30:20 +09:00
README-bot
66b608b2f9 Updated README.md 2023-12-15 15:39:58 +00:00
Stefan Haller
4ee01d153b fix(config): add yaml:"options" struct tag to CustomCommandPrompt.[]Options (#3163) 2023-12-15 16:39:43 +01:00
Emre Deger
79e04fad9a fix(config): add yaml struct tag to CustomCommandPrompt.[]Options
add `yaml` struct tag for fixing uppercase issue on json schema
2023-12-15 07:29:48 +03:00
README-bot
6778bc04a3 Updated README.md 2023-12-10 15:07:02 +00:00
Stefan Haller
d548f857a4 Fall back to WithWaitingStatus if item is not visible (#3083) 2023-12-10 16:06:49 +01:00
Stefan Haller
f99c59b6d5 Fall back to WithWaitingStatus if item is scrolled out of view 2023-12-10 16:03:25 +01:00
Stefan Haller
0fd4983c66 Fall back to WithWaitingStatus if view showing the item is not visible 2023-12-10 15:57:51 +01:00
Stefan Haller
240948b882 Return only visible views from TopViewInWindow
Without this it's not reliably possible to ask whether a given view is visible
by asking

  windowHelper.TopViewInWindow(context.GetWindowName()) == context.GetView()

because there could be transient, invisible contexts after it in the Z order.

I guess it's a bit of a coincidence that this has never been a problem so far.
2023-12-10 15:57:51 +01:00
README-bot
cf82e69bbe Updated README.md 2023-12-09 14:40:36 +00:00
Stefan Haller
653e59a3d5 Make move up/down blocking (#2966) 2023-12-09 15:40:23 +01:00
Stefan Haller
e342860ef1 Add WithWaitingStatusSync for reverting commits 2023-12-09 15:28:41 +01:00
Stefan Haller
569adae6a2 Use WithWaitingStatusSync for move commit up/down 2023-12-09 15:28:40 +01:00
Stefan Haller
79fe885dcd Add WithWaitingStatusSync 2023-12-09 15:28:40 +01:00
Stefan Haller
a46f26e148 Bump gocui 2023-12-09 15:23:40 +01:00
Stefan Haller
ca4b8b25f0 Fix bottom line alignment (#3076) 2023-12-09 11:57:06 +01:00
Jesse Duffield
dad2c5fa52 Add tests for window arrangement code
The output of the GetWindowDimensions function is hard to understand just by looking at it,
so I've added a helper function in the tests to render the window layout as text, so that
in order to create a new test you just come up with some args and paste the output as the
expected output.

This has the same downsides that any snapshot-based testing has: it's more brittle than
targeted assertions. But it is much easier to make sense of these snapshots than it is
to make sense of more fine-grained assertions, and I like the fact that these tests can
serve as documentation.
2023-12-09 11:53:52 +01:00
Jesse Duffield
8a08abcd35 Refactor window arrangement helper to use pure function
This will make it easier to test the file
2023-12-09 11:18:28 +01:00
Jesse Duffield
b96befa250 Layout the bottom line view using spacer views
We are also removing the single-character padding on the left/right edges of the bottom
line because it's unnecessary

Unfortunately we need to create views for each spacer: it's not enough to just
layout the existing views with padding inbetween because gocui only renders
views meaning if there is no view in a given position, that position will just
render whatever was there previously (at least that's what I recall from talking
this through with Stefan: I could be way off).

Co-authored-by: Stefan Haller <stefan@haller-berlin.de>
2023-12-09 11:18:28 +01:00
Stefan Haller
8cc820668a Fix an incorrect comment
It sounds like at some point we only showed a slash as the search prompt, but I
dug a bit through the history and couldn't find a state of the code where that
was the case. (shrug)
2023-12-09 11:18:28 +01:00
Luka Markušić
ccb1ee04a5 fix: MacOS default path misspelling (#3148) 2023-12-07 10:07:52 +01:00
ZeroMask
d00936fb4e fix: MacOS default path misspelling 2023-12-07 11:52:39 +03:00
README-bot
e84d5acd23 Updated README.md 2023-12-07 07:35:43 +00:00
Stefan Haller
a8a4211d2b Add a copy-to-clipboard menu to the file view (with diff copy options) (#3104) 2023-12-07 08:35:28 +01:00
AzraelSec
6907816af9 chore: update jsonschema 2023-12-07 08:30:03 +01:00
AzraelSec
38db574de9 chore: update cheatsheets 2023-12-07 08:30:03 +01:00
AzraelSec
c7012528fc feat: introduce a copy menu into the file view 2023-12-07 08:30:03 +01:00
Jesse Duffield
2162e5ff64 Re-enable 'Unset upstream' option when upstream branch is missing (#3086) 2023-12-06 15:58:11 +11:00
README-bot
f40f5710f0 Updated README.md 2023-12-06 04:58:04 +00:00
Jesse Duffield
97940cae10 Updated installation instruction for Gentoo (#3113) 2023-12-06 15:57:50 +11:00
Stefan Haller
1555503493 Add UserConfig jsonschema generation script (#3039) 2023-12-02 13:27:37 +01:00
Karim Khaleel
1a035db4c8 Add UserConfig jsonschema generation script 2023-12-02 10:46:24 +01:00
Karim Khaleel
df5b3693d6 Add invopop/jsonschema fork 2023-12-02 10:46:24 +01:00
Stefan Haller
b123719107 Update cheatsheets (#3143) 2023-12-02 10:41:08 +01:00
Stefan Haller
6ec109c15a Update cheatsheets
This was forgotten in #3046.
2023-12-02 10:36:15 +01:00
Jesse Duffield
dee1ff007d fixed typo in test description (#3101) 2023-12-02 09:37:49 +11:00
README-bot
02b739743a Updated README.md 2023-12-01 22:35:12 +00:00
Jesse Duffield
f5361fdcb4 commmit - enhance docs for keybinding 'c' for local branch (#3046) 2023-12-02 09:34:58 +11:00
Jesse Duffield
b86d5bd688 Update README.md 2023-11-30 19:46:12 +11:00
README-bot
4bfffa69ff Updated README.md 2023-11-30 08:24:43 +00:00
Jesse Duffield
f9b4bcde38 Capture test code coverage stats (#3135) 2023-11-30 19:21:22 +11:00
Jesse Duffield
aaecd6cc40 Add coverage arg for integration tests
This PR captures the code coverage from our unit and integration tests. At the
moment it simply pushes the result to Codacy, a platform that assists with
improving code health. Right now the focus is just getting visibility but I want
to experiment with alerts on PRs when a PR causes a drop in code coverage.

To be clear: I'm not a dogmatist about this: I have no aspirations to get to
100% code coverage, and I don't consider lines-of-code-covered to be a perfect
metric, but it is a pretty good heuristic for how extensive your tests are.

The good news is that our coverage is actually pretty good which was a surprise
to me!

As a conflict of interest statement: I'm in Codacy's 'Pioneers' program which
provides funding and mentorship, and part of the arrangement is to use Codacy's
tooling on lazygit. This is something I'd have been happy to explore even
without being part of the program, and just like with any other static analysis
tool, we can tweak it to fit our use case and values.

## How we're capturing code coverage

This deserves its own section. Basically when you build the lazygit binary you
can specify that you want the binary to capture coverage information when it
runs. Then, if you run the binary with a GOCOVERDIR env var, it will write
coverage information to that directory before exiting.

It's a similar story with unit tests except with those you just specify the
directory inline via `-test.gocoverdir`.

We run both unit tests and integration tests separately in CI, _and_ we run them
parallel with different OS's and git versions. So I've got each step uploading
the coverage files as an artefact, and then in a separate step we combine all
the artefacts together and generate a combined coverage file, which we then
upload to codacy (but in future we can do other things with it like warn in a PR
if code coverage decreases too much).

Another caveat is that when running integration tests, not only do we want to
obtain code coverage from code executed by the test binary, we also want to
obtain code coverage from code executed by the test runner. Otherwise, for each
integration test you add, the setup code (which is run by the test runner, not
the test binary) will be considered un-covered and for a large setup step it may
appear that your PR _decreases_ coverage on net. Go doesn't easily let you
exclude directories from coverage reports so it's better to just track the
coverage from both the runner and the binary.

The binary expects a GOCOVERDIR env var but the test runner expects a
test.gocoverdir positional arg and if you pass the positional arg it will
internally overwrite GOCOVERDIR to some random temp directory and if you then
pass that to the test binary, it doesn't seem to actually write to it by the
time the test finishes. So to get around that we're using LAZYGIT_GOCOVERDIR and
then within the test runner we're mapping that to GOCOVERDIR before running the
test binary. So they both end up writing to the same directory. Coverage data
files are named to avoid conflicts, including something unique to the process,
so we don't need to worry about name collisions between the test runner and the
test binary's coverage files. We then merge the files together purely for the
sake of having fewer artefacts to upload.

## Misc

Initially I was able to have all the instances of '/tmp/code_coverage' confined
to the ci.yml which was good because it was all in one place but now it's spread
across ci.yml and scripts/run_integration_tests.sh and I don't feel great about
that but can't think of a way to make it cleaner.

I believe there's a use case for running scripts/run_integration_tests.sh
outside of CI (so that you can run tests against older git versions locally) so
I've made it that unless you pass the LAZYGIT_GOCOVERDIR env var to that script,
it skips all the code coverage stuff.

On a separate note: it seems that Go's coverage report is based on percentage of
statements executed, whereas codacy cares more about lines of code executed, so
codacy reports a higher percentage (e.g. 82%) than Go's own coverage report
(74%).
2023-11-30 12:58:41 +11:00
Jesse Duffield
7e5f25e415 Use args struct for RunTests
There were too many position arguments
2023-11-29 11:39:10 +11:00
Stefan Haller
d8059d7f7d Use a PTY when calling external diff command (#3120) 2023-11-22 12:51:02 +01:00
尼诺
0f2b79a1d4 Use a PTY when calling external diff command
This is important for communicating the view size to the external command.
e.g. The columns in difft's side-by-side mode are aligned correctly.
2023-11-22 12:08:05 +01:00
README-bot
bb87642aee Updated README.md 2023-11-19 16:10:18 +00:00
Stefan Haller
4a5b3eaa52 Fix go.mod file (#3118) 2023-11-19 17:10:03 +01:00
Stefan Haller
1b4e76797f Add "go mod tidy" check to CI
This should catch errors like this earlier.
2023-11-18 16:03:51 +01:00
Stefan Haller
58971182ca Fix go.mod file (go-difflib dependency should be indirect)
This broke with commit 7af371701d, but nobody noticed yet.
2023-11-18 16:01:03 +01:00
Hamed Benazha
9427a85805 Update README.md to contain new information to install it on gentoo
I changed the installation of method for the Gentoo distribution from a user owned overlay to a community owned one. GURU is the community owned overlay, it's safer to use and easier to maintain
2023-11-10 09:26:30 +01:00
Luka Markušić
d145e818d0 Fix unsetting upstream when it doesn't exist 2023-11-04 23:46:27 +01:00
Luka Markušić
e0fc8fe25b Introduce failing "UnsetUpstream" test 2023-11-04 23:45:21 +01:00
Luka Markušić
bb705d91a4 Rename integration test "ResetUpstream"
We are unsetting upstream in it, not resetting to upstream
2023-11-04 23:18:38 +01:00
schuebel
738fa286b2 fixed typo in test description 2023-10-30 14:17:34 +01:00
README-bot
1d1b8cc01f Updated README.md 2023-10-27 04:14:57 +00:00
Jesse Duffield
c357284e1a Add Warp link to readme
Adding warp to the readme as they are trialling out sponsoring the project.
2023-10-27 04:14:40 +00:00
README-bot
232596b83d Updated README.md 2023-10-26 07:45:25 +00:00
Jesse Duffield
1c1d558cc7 Add Codacy badge
I applied to the Codacy Pioneers program for funding and mentorship and I got accepted. Part of the terms is to show the codacy report badge in the readme. Thank God it's an A!
2023-10-26 07:45:08 +00:00
README-bot
dffb16ed96 Updated README.md 2023-10-24 15:27:07 +00:00
Stefan Haller
df8ce76bd6 Update Stacked_Branches.md (#3090) 2023-10-24 17:26:49 +02:00
Alan Potter
4d18b62c54 Update Stacked_Branches.md
Fix a typo.
2023-10-24 05:32:29 -04:00
README-bot
8193731a82 Updated README.md 2023-10-18 10:28:08 +00:00
Jesse Duffield
1a6d062192 Color file icons (#3080) 2023-10-18 21:27:53 +11:00
Jesse Duffield
1ff13cdfc6 Advise against raising pull requests from master branch 2023-10-18 21:21:50 +11:00
aashish2057
19e8cafe41 create iconProperties struct and convert iconMaps to use iconProperties 2023-10-18 21:21:36 +11:00
README-bot
cbb5fe6007 Updated README.md 2023-10-16 11:30:40 +00:00
Stefan Haller
c4fc30c243 Truncate branch names to make branch status always visible (#3075) 2023-10-16 13:30:24 +02:00
Stefan Haller
117aa1dcc6 Advise developers to use a nerd font in their editor 2023-10-16 13:15:05 +02:00
Stefan Haller
c550737a4f Truncate long branch names to make branch status visible 2023-10-16 13:15:05 +02:00
Stefan Haller
9e37ae3f5d Make the window a little wider for headless integration tests
100 was an unrealistically narrow width; make it a little wider so that we will
have to truncate things less often.
2023-10-16 09:03:07 +02:00
Stefan Haller
c89ef8b84a Make it possible to set the nerd fonts version to "off"
We don't need this for production code, but it will be needed for tests in the
next commit.
2023-10-16 09:03:07 +02:00
Stefan Haller
23befdd13a Pass "now" into utils.Loader
This makes it possible to write deterministic tests for views that use it.
2023-10-16 09:03:07 +02:00
Stefan Haller
58a83b0862 Remove special code to rerender views on screen mode change
The previous commit handles this case too.
2023-10-16 09:03:07 +02:00
Stefan Haller
d5b4f7bb3e Rerender certain views when their width changes
Situations where a view's width changes:
- changing screen modes
- enter staging or patch building
- resizing the terminal window

For the first of these we currently have special code to force a rerender, since
some views render different content depending on whether they are in full-screen
mode. We'll be able to remove that code now, since this new generic mechanism
takes care of that too.

But we will need this more general mechanism for cases where views truncate
their content to the view width; we'll add one example for that later in this
branch.
2023-10-16 09:03:07 +02:00
README-bot
3cee4de39c Updated README.md 2023-10-15 07:46:45 +00:00
Stefan Haller
f609a04671 Add 'lvim' editor preset for lunarvim (#3074) 2023-10-15 09:46:30 +02:00
zottelsheep
7ffb6ffb0f Add 'lvim' editor preset for lunarvim
Add 'lvim' as a new standardTerminalEditorPreset, since lunarvim uses an alias for nvim.
2023-10-14 15:04:23 +02:00
Stefan Haller
3691856021 Re-apply filter when model changes (#3058) 2023-10-10 08:43:48 +02:00
Stefan Haller
b5ca6a3add When refreshing models, re-apply active filter for the corresponding view 2023-10-10 08:37:30 +02:00
Stefan Haller
ecaa4846f1 Fix crash when trying to filter the list of remotes (#3059) 2023-10-10 08:36:47 +02:00
Stefan Haller
787f9966ec Fix crash when trying to filter the list of remotes
This seems to be a left-over from an earlier iteration of the code. Removing it
fixes the crash.
2023-10-10 08:33:18 +02:00
Stefan Haller
013cfc77a1 Show sync status in branches list (#3021) 2023-10-10 08:32:42 +02:00
Jesse Duffield
16f7b01fec Add disabled compat for user config (#2833) (#3060) 2023-10-10 16:49:31 +11:00
Karim Khaleel
421c6565f9 Update wording in disable keybindings test
Co-authored-by: Jesse Duffield <jessedduffield@gmail.com>
2023-10-10 08:38:15 +03:00
Karim Khaleel
d02deeefd8 Add disabled compat for user config (#2833)
Treat <disabled> setting as equivalent to "null"
in keybindings user configs.
2023-10-09 22:34:50 +03:00
Stefan Haller
235f5bb221 Avoid rendering branches view twice when refreshing
refreshWorktrees re-renders the branches view, because the branches view shows
worktrees against branches. This means that when both BRANCHES and WORKTREES are
requested to be refreshed, the branches view would be rendered twice in short
succession. This causes an ugly visual glitch when force-pushing a branch,
because when pushing is done, we would see the ↑4↓9 status come back from under
the Pushing status for a brief moment, to be replaced with a green checkmark a
moment later.

Fix this by including the worktree refresh in the branches refresh when both are
requested. This means that the two are no longer running in parallel for an
async refresh, but hopefully that's not so bad.
2023-10-08 18:45:36 +02:00
Stefan Haller
be3b4bd791 Remove sync mutex
I'm pretty convinced we don't need it. Git itself does a good job of making sure
that concurrent operations don't corrupt anything.
2023-10-08 18:45:36 +02:00
Stefan Haller
67d6447e12 Disallow pulling/pushing a branch while the branch is pushed or pulled 2023-10-08 18:45:36 +02:00
Stefan Haller
fd9d7cb7bb Disallow checking out another branch while the current one is being pulled 2023-10-08 18:45:36 +02:00
Stefan Haller
3d6965ccbb Add inline status for pushing tags and deleting remote tags 2023-10-08 18:45:36 +02:00
Stefan Haller
707fa37160 Add inline status for pushing/pulling/fast-forwarding branches
When pulling/pushing/fast-forwarding a branch, show this state in the branches
list for that branch for as long as the operation takes, to make it easier to
see when it's done (without having to stare at the status bar in the lower
left).

This will hopefully help with making these operations feel more predictable, now
that we no longer show a loader panel for them.
2023-10-08 18:45:36 +02:00
Stefan Haller
7075b66bc6 Add WithInlineStatus helper function
Very similar to WithWaitingStatus, except that the status is shown in a view
next to the affected item, rather than in the status bar.

Not used by anything yet; again, committing separately to get smaller commits.
2023-10-08 18:45:36 +02:00
Stefan Haller
9d55d71fdd Add GetItemOperation/SetItemOperation/ClearItemOperation to IStateAccessor
Not used by anything yet; committing this separately in the interest of having
smaller independent commits.
2023-10-08 18:30:57 +02:00
Stefan Haller
cc9a20c4ab Don't report errors from within a WithWaitingStatus
We can just return our error to WithWaitingStatus, it will take care of
reporting it.
2023-10-08 18:30:34 +02:00
README-bot
c39fafe6ec Updated README.md 2023-10-04 23:33:09 +00:00
Jesse Duffield
2a11725749 Remove redundant len check (#3051) 2023-10-05 10:32:53 +11:00
Eng Zer Jun
deed9eb18e Remove redundant len check
From the Go specification [1]:

  "3. If the map is nil, the number of iterations is 0."

`len` returns 0 if the map is nil [2]. Therefore, checking `len(v) > 0`
before a loop is unnecessary.

[1]: https://go.dev/ref/spec#For_range
[2]: https://pkg.go.dev/builtin#len

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2023-10-04 21:03:26 +08:00
Sebastian
50b49ebeb1 Merge branch 'jesseduffield:master' into feature/keybinding-branch-recent 2023-10-04 09:42:53 +02:00
Sebastian Mangelsen
a74c6eef40 adjust the text to received review comments 2023-10-04 09:41:00 +02:00
README-bot
a3759c65e4 Updated README.md 2023-10-03 19:20:39 +00:00
Stefan Haller
519760077b Add Micro editor preset (#3049) 2023-10-03 21:20:21 +02:00
Nikita Karamov
8390622f70 Add Micro editor preset 2023-10-03 19:42:28 +02:00
README-bot
a04fbafcfd Updated README.md 2023-10-03 09:35:18 +00:00
Stefan Haller
4fe8dee40f Band-aid fix for submodule/reset.go test failure (#3047) 2023-10-03 11:34:59 +02:00
Stefan Haller
6fd80565c7 Band-aid fix for submodule/reset.go test failure
This is not a complete fix, but it's good enough to fix the spurious test
failures of submodule/reset.go. We have some vague hope to fix this in a more
sustainable way by somehow improving our concurrency model fundamentally, but
that's a more long-term undertaking, and it's annoying that this test fails so
often, so let's fix it in this way for now.
2023-10-03 09:36:46 +02:00
Sebastian Mangelsen
5ebd8ac7fe commmit - enhance docs for keybinding 'c' for local branch
- closes #3030
- mention that it supports '-'
- fix documentation and builtin help
2023-10-02 18:06:24 +02:00
README-bot
3cda1d03d9 Updated README.md 2023-10-01 06:05:28 +00:00
Stefan Haller
d4eb02fac0 Add ability to force portrait mode (#3037) 2023-10-01 08:05:13 +02:00
Louis DeLosSantos
9c72d8a2b0 Add ability to force portrait mode
A new gui config flag 'portraitMode':<string> is added to influence when
LazyGit stacks its UI components on top of one another.

The accepted values are 'auto', 'always', 'never'.

'auto': enter portrait mode when terminal becomes narrow enough

'always': always use portrait mode unconditional of the terminal
dimensions

'never': never use portraid mode

Signed-off-by: Louis DeLosSantos <louis.delos@gmail.com>
2023-09-30 20:57:38 +02:00
Jesse Duffield
4f3127ccb8 Update PR template to use go generate command (#3041) 2023-09-30 20:06:58 +10:00
Jesse Duffield
877c27722f add gofumpt to workspace settings 2023-09-30 19:46:03 +10:00
Jesse Duffield
0dda8b58d1 Update PR template to use go generate command 2023-09-30 19:45:55 +10:00
Jesse Duffield
e997d1ae5d Add comments in user config struct (#3040) 2023-09-30 19:39:42 +10:00
Jesse Duffield
3e2ef84d56 Ignore deprecation checks in linter
This is pretty funny: the staticcheck linter gets mad if we use a field which is marked
in a comment as being deprecated. But it tripped on my own comment saying that a field
is deprecated in terms of the user config!

Obviously we have to make use of this field, otherwise we would just remove it entirely
rather than mark it as deprecated, so I'm silencing this lint.

I doubt this lint would actually come in handy in other cases (like when using a third
party package) and worst case scenario we just end up fixing the problem when we
try to upgrade the package and the deprecated field is now gone).
2023-09-30 19:24:59 +10:00
Jesse Duffield
b2eccd6fe8 Add comments in user config struct
We're going to make this user config struct a more authoritative source of truth.

Some of these fields weren't actually explained anywhere so I've added explanations.

In places where a lot of explanation is required I've linked to existing explanations in other docs.
2023-09-30 19:23:52 +10:00
Stefan Haller
cc25a3b8c5 Change Makefile to build non-optimized (#3028) 2023-09-30 10:59:22 +02:00
Stefan Haller
e93d945dba Change Makefile to build non-optimized 2023-09-30 10:50:32 +02:00
README-bot
246e08096f Updated README.md 2023-09-30 08:46:30 +00:00
Stefan Haller
860a52a736 Use go:generate for cheatsheet (#3035) 2023-09-30 10:46:16 +02:00
Stefan Haller
18d8b29461 Make test_list_generator.go print what it's doing
It's confusing if the cheatsheet generator prints output but this one doesn't.
2023-09-29 20:40:15 +02:00
Stefan Haller
7af371701d Use go:generate for generating cheatsheets
This has several benefits:
- it's less code
- we're using the same mechanism to generate all our auto-generated files, so if
  someone wants to add a new one, it's clear which pattern to follow
- we can re-generate all generated files with a single command
  ("go generate ./...", or "make generate")
- we only need a single check on CI to check that all files are up to date (see
  previous commit)
2023-09-29 20:38:29 +02:00
Stefan Haller
5ccc95b76f Generalize the CI check for the test list to all auto-generated files
At the moment, test_list.go is the only file that we generate using go:generate.
We will add another one in the next commit though, and we might add even more in
the future; it's useful to have a single check on CI that checks them all.
2023-09-29 20:20:09 +02:00
README-bot
cdb1d76484 Updated README.md 2023-09-28 08:04:37 +00:00
Stefan Haller
9e423e949c Improve debugging of integration tests (#3029)
Several improvements to make debugging integration tests work better.
2023-09-28 10:04:23 +02:00
Stefan Haller
e1ceb6892a Disable deadlock reporting when debugging an integration test 2023-09-28 10:03:53 +02:00
Stefan Haller
40b8557608 Disable the 40-second timeout for integration tests when debugging
Pausing at breakpoints and stepping through code can often take longer than 40s,
so the timeout is annoying when debugging.
2023-09-28 10:03:53 +02:00
Stefan Haller
92e107f52d Use constant for WAIT_FOR_DEBUGGER env var 2023-09-28 10:03:53 +02:00
Stefan Haller
2f6a87df98 Build lazygit without optimizations and inlining when debugging
This makes the debugging experience better.
2023-09-28 10:03:53 +02:00
Jesse Duffield
2c29577e3c Respect $GIT_WORK_TREE and $GIT_DIR env vars (fix #3010). (#3024) 2023-09-26 23:52:19 +10:00
BZ
e72559bb27 respect and env vars 2023-09-25 12:20:12 +02:00
Stefan Haller
6da1cf87b1 Support passing -race flag to integration tests (#3019) 2023-09-25 09:14:38 +02:00
Stefan Haller
508b869773 Pass MAKECMDGOALS to make integration-test-tui
We need this to be able to pass the "-race" argument, i.e.

  make integration-test-tui -- -race
2023-09-25 09:09:41 +02:00
Stefan Haller
59cc6843e6 Print race detector logs after running a test with -race 2023-09-25 09:09:41 +02:00
Stefan Haller
f108fd2236 Support -race arg when running integration tests to turn on go's race detector
For the "cli" and "tui" modes of the test runner there's a "-race" parameter to
turn it on; for running tests on CI with go test, you turn it on by setting the
environment variable LAZYGIT_RACE_DETECTOR to a non-empty value.
2023-09-25 09:09:41 +02:00
Stefan Haller
8081b59a02 Allow passing multiple flags to the cli runner
This is useful for example to pass both -slow and -debug. Since we're about to
add yet another flag in the next commit, it becomes even more important. Plus,
it makes the code a little nicer too.
2023-09-25 09:09:41 +02:00
Stefan Haller
26d180a50a Fix minor resource leak in runCmdHeadless
We still want to close the pty if the command failed.
2023-09-25 09:09:41 +02:00
Jesse Duffield
10fe872c71 Fix issue where active search inappropriately changed selected line (#3022) 2023-09-25 16:43:47 +10:00
Jesse Duffield
c74448f00d Don't select current search result when showing search status
Previously there was no way to render a view's search status without also moving the cursor
to the current search match. This caused issues where we wanted to display the status
after leaving the view and coming back, or when beginning a new search from within the
view.

This commit separates the two use cases so we only move the cursor when we're actually
selecting the next search match
2023-09-25 16:37:59 +10:00
Jesse Duffield
41ab7c44a0 Use upstream branch when opening pull requests (#2693)
- **PR Description**

Should probably solve #2691

- **Please check if the PR fulfills these requirements**

* [x] Cheatsheets are up-to-date (run `go run scripts/cheatsheet/main.go
generate`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [x] You've read through your own file changes for silly mistakes etc
2023-09-25 11:03:15 +10:00
README-bot
3589a43682 Updated README.md 2023-09-25 00:24:22 +00:00
Jesse Duffield
ad70341139 Add menu to rebase onto selected branch remote upstream (#3020) 2023-09-25 10:24:06 +10:00
AzraelSec
ea93df571d feat: add a menu to rebase current branch to a target branch upstream 2023-09-24 20:13:59 +02:00
AzraelSec
bc21921001 chore: rename branch upstream view options method 2023-09-22 12:19:38 +02:00
Stefan Haller
07cbb62510 Replace loader panels with waiting status (pull/push/fetch) (#2973) 2023-09-20 14:07:25 +02:00
Stefan Haller
fc868cdda5 Shorten the waiting status for fast-forwarding a branch
Now that we no longer show it in a loader panel, but in the app status view,
it's awkwardly long (the loading animation is much further to the right than for
other waiting status texts). Hopefully seeing just "Fast-forwarding <branch>" is
enough to be able to tell what's happening.
2023-09-20 13:56:06 +02:00
Stefan Haller
864a9ada57 Remove unused WithLoaderPanel code 2023-09-20 13:30:49 +02:00
Stefan Haller
f3e9d50d94 Use WithWaitingStatus instead of WithLoaderPanel for pull/push/fetch 2023-09-20 13:30:49 +02:00
Stefan Haller
cdad0b998e Add constant for LoaderAnimationInterval
Since Loader and renderAppStatus need to agree on it, it helps for it to be a
constant in case we want to change it.
2023-09-20 13:30:49 +02:00
Stefan Haller
64012d67a9 Remove unused class FakePopupHandler 2023-09-20 13:30:49 +02:00
Stefan Haller
33d9d4dbf1 Hide waiting status during credentials prompt (#3016) 2023-09-20 13:30:15 +02:00
Stefan Haller
4c5e250ed8 Add integration test for deleting a remote branch with credentials prompt
This test is interesting because it shows a credentials prompt inside a
WithWaitingStatus. Prior to this branch this test would have hung forever.
2023-09-20 13:29:30 +02:00
Stefan Haller
1359fa14c1 When pausing a task during a waiting status, hide the status while paused
We do this for two reasons:
- when popping up a credentials prompt, it looks distracting if the waiting
  status keeps spinning while the user is typing the password
- the task that updates the waiting status periodically would keep the program
  busy, so integration tests would wait forever for the program to become idle
  again
2023-09-20 13:29:30 +02:00
Stefan Haller
c222a618a8 Extract WaitingStatusHandle 2023-09-20 13:29:11 +02:00
Stefan Haller
05c32e292e Extract StatusManager.addStatus method
Avoids a bit of code duplication.
2023-09-20 11:27:50 +02:00
README-bot
fb4f742416 Updated README.md 2023-09-20 06:10:06 +00:00
Jesse Duffield
276438b601 Add history for search view (#2877) 2023-09-20 16:09:53 +10:00
Karim Khaleel
edec116ceb Add search history
Add search history for filterable and searchable views.
2023-09-20 08:35:41 +03:00
Stefan Haller
1aae1772ce Allow cherry-picking commits during a rebase (#3013) 2023-09-19 07:15:10 +02:00
Stefan Haller
a642395e9f Allow cherry-picking commits during a rebase
This can be useful when you know that a cherry-picked commit would conflict at
the tip of your branch, but doesn't at the beginning of the branch (or
somewhere in the middle). In that case you want to be able to edit the commit
before where you want to insert the cherry-picked commits, and then paste to
insert them into the todo list at that point.
2023-09-18 10:50:19 +02:00
Stefan Haller
70bfeddc90 Add StatusCommands.IsInNormalRebase and IsInInteractiveRebase
... and implement RebaseMode in terms of these.
2023-09-18 10:50:19 +02:00
Stefan Haller
e2a966443b Add a DisabledReason mechanism for menu items and keybindings (#2992) 2023-09-18 10:26:11 +02:00
Stefan Haller
0b13c3ca87 Disabled paste when there are no copied commits 2023-09-18 10:20:23 +02:00
Stefan Haller
8b6766de79 Use DisabledReason for commits panel commands 2023-09-18 10:20:23 +02:00
Stefan Haller
c9371f812f Use DisabledReason for rebasing a branch onto itself 2023-09-18 10:20:23 +02:00
Stefan Haller
e592d81b60 Add Enabled func to Binding 2023-09-18 10:20:23 +02:00
Stefan Haller
f2f50ccf75 Use DisabledReason for upstream options items 2023-09-18 10:15:11 +02:00
Stefan Haller
75aed98c35 Use DisabledReason when deleting branches is not possible
Two cases: trying to delete the currently checked-out branch, or deleting the
upstream of a branch that doesn't have one.
2023-09-18 10:15:11 +02:00
Stefan Haller
7f9818cfa2 Add DisabledReason field to MenuItem
This is useful to disable items that are not applicable right now because of
some condition (e.g. the "delete branch" menu item when the currently
checked-out branch is selected).

When a DisabledReason is set on a menu item, we
- show it in a tooltip (below the regular tooltip of the item, if it has one)
- strike through the item's key, if it has one
- show an error message with the DisabledReason if the user tries to invoke the
  command
2023-09-18 10:15:11 +02:00
README-bot
679148449a Updated README.md 2023-09-18 08:14:59 +00:00
Stefan Haller
bc00aeb10d Rename test/results to test/_results (#3012) 2023-09-18 10:14:43 +02:00
Luka Markušić
4d258bd981 Use UpstreamBranch for opening pull requests 2023-09-18 13:40:52 +10:00
Stefan Haller
c465b0f2ff Rename test/results to test/_results
This prevents commands like "go test ./..." from looking into it, and it
prevents VS Code's Problems panel from showing errors about the go files in that
folder.
2023-09-15 18:04:20 +02:00
README-bot
25160b671e Updated README.md 2023-09-13 07:17:12 +00:00
Jesse Duffield
20bfa42792 Use Error method to handle commits url copy from unknown service (#3007) 2023-09-13 17:16:53 +10:00
AzraelSec
5a740e34c7 fix: use Error method to handle the commit url copy from unknown service 2023-09-12 19:06:08 +02:00
Stefan Haller
0aad599a9b Various debugging improvements (#3000) 2023-09-11 08:27:03 +02:00
Stefan Haller
b6c892a08a Provide a simple way to debug an integration test 2023-09-11 08:17:58 +02:00
Stefan Haller
28d12e4e5d Add debug configuration to attach to a running lazygit process
I often find it more convenient to start a lazygit process in a terminal window
and then attach to it, rather than have VS Code launch one for me.

Note that this doesn't work with "go run main.go". It does work with "make run",
however.

Make sure there's only one lazygit process running, otherwise VS Code will open
a chooser with all the running processes to pick one from, but it's pretty much
impossible to tell which is which.
2023-09-10 11:47:25 +02:00
Stefan Haller
5d5e24a48e Change "make run" to do a build and then launch lazygit
As far as I can tell, there's not much of a difference in behavior between the
two. The advantage of doing it this way is that you can attach a debugger to the
running lazygit process; see next commit.
2023-09-10 11:47:25 +02:00
Stefan Haller
de598e55a6 Hide system goroutines in callstack
I have never found a reason to see them, and they just pollute the stack window
unnecessarily.
2023-09-10 11:47:25 +02:00
Stefan Haller
0fd8392067 Format launch.json with Prettier 2023-09-10 11:47:25 +02:00
Jesse Duffield
67ac2c5d9b Change the default of the "gui.borders" config to "rounded" (#2998) 2023-09-10 12:23:25 +10:00
Jesse Duffield
7626fd7df3 Add co-author to commits (#2912) 2023-09-10 11:38:16 +10:00
Orlando Maussa
db409fa69f Add coauthor (#2)
Add co-author to commits

Add addCoAuthor command for commits

- Implement the `addCoAuthor` command to add co-authors to commits.
- Utilize suggestions helpers to populate author names from the suggestions list.
- Added command to gui at `LocalCommitsController`.

This commit introduces the `addCoAuthor` command, which allows users to easily add co-authors to their commits. The co-author names are populated from the suggestions list, minimizing the chances of user input errors. The co-authors are added using the Co-authored-by metadata format recognized by GitHub and GitLab.
2023-09-09 07:18:47 -05:00
Stefan Haller
5b8a8d356c Change the default of the "gui.borders" config to "rounded"
Most people seem to agree that it looks better than the sharp edges of "single".
2023-09-09 10:42:24 +02:00
Stefan Haller
d7e2ca3f10 Add jump-to-panel label config setting (#2993) 2023-09-09 09:55:52 +02:00
Maria José Solano
387fbf6ab6 feat: add jump-to-panel label setting 2023-09-09 09:45:08 +02:00
Stefan Haller
917eb88617 Bump gocui 2023-09-09 09:44:50 +02:00
README-bot
005827395d Updated README.md 2023-09-09 07:35:14 +00:00
Jesse Duffield
7f9fa64074 Replace whitespace with '-' when renaming a branch (#2990) 2023-09-09 17:34:57 +10:00
README-bot
ab06a1c85c Updated README.md 2023-09-06 06:45:15 +00:00
Stefan Haller
37048911ca Support to reset the current branch to a selected branch upstream (#2940) 2023-09-06 08:45:00 +02:00
AzraelSec
2b7b6f71ee feat: add a menu to reset current branch to a target branch upstream 2023-09-06 08:40:07 +02:00
AzraelSec
47d422bb8a chore: rename "Set/Unset upstream" menu to "Upstream Options"
This should already have been done when adding the "View divergence from
upstream" command, but now we're going to add yet another item to the menu that
is unrelated to setting or unsetting the upstream.
2023-09-06 00:23:35 +02:00
Cal Courtney
c3ca77d6bf Replace whitespace with '-' when renaming a branch 2023-09-05 14:57:18 +01:00
README-bot
a3cd1e93be Updated README.md 2023-09-05 12:01:12 +00:00
Stefan Haller
4cf8d81155 Save diff context size in state.yml instead of config.yml (#2969) 2023-09-05 14:00:55 +02:00
Stefan Haller
7774fe0ab3 Move diff context size from UserConfig to AppState 2023-09-05 13:55:30 +02:00
Stefan Haller
f7db17f7d0 Load defaults for AppState before reading from yaml
So far this hasn't been necessary because all defaults were zero values. We're
about to add the first non-zero value though, and it's important that it is
initialized correctly for users who have a state.yml that doesn't have it yet.
2023-09-04 17:50:49 +02:00
Stefan Haller
1106981827 Extract a SaveAppStateAndLogError function
It seems that most actions that change a state option and resave the state want
to just log the error.
2023-09-04 17:50:49 +02:00
Stefan Haller
1dac4158e9 Don't pass ignoreWhitespace to git commands
Now that AppState is available via common.Common, they can take it from there.
2023-09-04 17:50:49 +02:00
Stefan Haller
18c5780485 Add AppState to common.Common 2023-09-04 17:48:39 +02:00
README-bot
e895052437 Updated README.md 2023-09-04 14:58:07 +00:00
Stefan Haller
ade8d78c63 Add support for external diff commands (e.g. difftastic) (#2868) 2023-09-04 16:57:49 +02:00
Stefan Haller
2e74b7177e Fix keybinding for editing config file 2023-09-04 16:52:30 +02:00
Stefan Haller
6266e19623 Add support for external diff commands (e.g. difftastic) 2023-09-04 16:52:30 +02:00
Stefan Haller
c67aa49856 Add explicit --no-ext-diff arg to CommitCommands.ShowCmdObj
We do this for ShowFileDiffCmdObj and WorktreeFileDiffCmdObj too, so why not
here.
2023-09-04 13:16:00 +02:00
README-bot
3a54089859 Updated README.md 2023-09-04 07:45:52 +00:00
Stefan Haller
e2c447b8d0 Improve prompts when amending commits (#2980) 2023-09-04 09:45:34 +02:00
Stefan Haller
843e12286f Improve prompts when amending commits
This fixes two minor problems with the prompts:

1. When pressing shift-A in the local commits view, it would first prompt
   whether to stage all files, and then it would prompt whether to amend the
   commit at all. This doesn't make sense, it needs to be the other way round.

2. When pressing shift-A on the head commit in an interactive rebase, we would
   ask whether they want to amend the last commit, like when pressing shift-A in
   the files view. While this is technically correct, the fact that we're
   amending the head commit in this case is just an implementation detail, and
   from the user's point of view it's better to use the same prompt as we do for
   any other commit.

To fix these, we remove the confirmation panel from AmendHelper.AmendHead() and
instead add it at the two call sites, so that we have more control over this.
2023-09-01 18:55:16 +02:00
README-bot
e60936e964 Updated README.md 2023-08-31 14:13:26 +00:00
Stefan Haller
b9cfd89b80 Fix escape not cancelling filter mode, but closing the menu instead (#2977) 2023-08-31 16:13:06 +02:00
Stefan Haller
de4224bbe4 Fix escape not cancelling filter mode, but closing the menu instead
When filtering is on in a menu, pressing esc should only cancel the filter, but
not close the menu.
2023-08-30 22:37:13 +02:00
README-bot
ce91de76e4 Updated README.md 2023-08-30 09:22:09 +00:00
Stefan Haller
acfce07aa0 Don't show toasts when running integration tests (#2975) 2023-08-30 11:21:52 +02:00
Stefan Haller
81216189e4 Don't show toasts when running integration tests
It's pointless because you can't check for them in tests anyway, so they
unnecessarily slow down the test run by two seconds for no reason.
2023-08-30 10:54:32 +02:00
Stefan Haller
2b26b380b6 Check for staged files for "Amend commit" and "Create fixup commit" (#2970) 2023-08-29 09:23:45 +02:00
Stefan Haller
1ba8d3060b Ensure committable files for "amend to" and "create fixup commit"
These would previously fail with confusing error messages when no files were
staged.

The diff is best viewed with "ignore whitespace" turned on.
2023-08-29 09:10:59 +02:00
Stefan Haller
f561007fb7 Extract a WithEnsureCommitableFiles function
This encapsulates the logic to make sure we have something to commit; which is
to
- auto-stage all files if no files are staged and the SkipNoStagedFilesWarning
config is on
- otherwise, prompt the user whether they want to stage all files
- error out if we don't have any files at all

Of these, the first one was only done when committing with the built-in commit
message panel; there's no reason why it shouldn't also be done when committing
with the editor, or when amending, and now it is.
2023-08-29 09:10:59 +02:00
Stefan Haller
a63d5891e2 Add command to show divergence from upstream (#2871) 2023-08-29 08:22:44 +02:00
Stefan Haller
df38e954f4 Add integration test for the new divergence log 2023-08-29 08:16:40 +02:00
Stefan Haller
ea532b4729 Add DoesNotContainAnyOf matcher 2023-08-29 08:16:40 +02:00
Stefan Haller
572d1b5920 Add "Show divergence from upstream" entry to Upstream menu in branches panel 2023-08-29 08:16:40 +02:00
Stefan Haller
e8fac6ca73 Extract a SubCommitsHelper from SwitchToSubCommitsController
We want to use it from BranchesController too.
2023-08-29 08:16:40 +02:00
Stefan Haller
4de3fadb00 Remove sub_commits_context's Title method
It implemented this because it wants to do custom truncation of the ref name;
however, we can achieve the same thing by passing the truncated ref name to our
DynamicTitleBuilder, which was previously unused.
2023-08-29 08:16:40 +02:00
Stefan Haller
12f24aa8b4 Add option RefToShowDivergenceFrom to GetCommitsOptions
Not used yet.
2023-08-29 08:16:40 +02:00
Stefan Haller
911aa7774b Don't return commits from setCommitMergedStatuses
Since the slice stores pointers to objects, and we're only modifying the objects
but not the slice itself, there's no need to return it and assign it back. This
will allow us to call the function for subslices of commits.

Also, move the condition that checks for an empty string inside the function;
we're going to call it from more than one place, so this makes it easier.
2023-08-29 08:16:40 +02:00
Stefan Haller
1fb0e1e151 Section headers in keybindings menu (#2911) 2023-08-29 08:14:30 +02:00
Stefan Haller
94bf279b5a Remove the magenta color on menu items that open a menu
It's distracting. But keep the ellipsis.
2023-08-29 08:04:47 +02:00
Stefan Haller
37381b610d Add sections (local, global) to the keybindings menu 2023-08-29 08:04:47 +02:00
Stefan Haller
6d4df57393 Add option to add sections to menus 2023-08-29 08:04:47 +02:00
Stefan Haller
3df01aaff0 Add a mechanism to insert non-model items into list contexts
Not used by anything yet.
2023-08-29 08:04:47 +02:00
Stefan Haller
4ee4f6f34b Make columnPositions include entries for removed columns
We will pass these positions back to clients for rendering non-model items, and
it's important that clients can consistently rely on them no matter which
columns were removed.
2023-08-28 14:21:06 +02:00
Stefan Haller
7953f7fa86 Make RenderDisplayStrings return the column positions
Not used by anything yet, but we'll need it later in this branch.
2023-08-28 14:21:06 +02:00
Stefan Haller
7a8df7795c Take removed columns into account when applying column alignments 2023-08-28 14:21:06 +02:00
Stefan Haller
aa493d3a9e Add failing test demonstrating bug with column alignments and removed columns
When columns to the left of a column with an alignment are removed, the
alignment applies to the wrong column. We'll fix this in the next commit.
2023-08-28 14:21:06 +02:00
Stefan Haller
72731f2c16 Change RenderDisplayStrings to return a slice of strings
We'll join them with newlines afterwards. This will make it easier to insert
other (non-model) items.
2023-08-28 14:21:06 +02:00
Stefan Haller
f680b6e82e Cleanup: use slices.Delete to delete elements from a slice
I find this much easier to read.
2023-08-28 14:21:06 +02:00
Stefan Haller
ec22570eac Add tests for renderLines
These are very simple yet, but we'll extend them in the next commits.
2023-08-28 14:21:06 +02:00
Stefan Haller
198ead7c14 Extract a ListRenderer struct
I'm doing this not so much because it's a great abstraction, but just because it
will make it much easier to write tests for it.
2023-08-28 14:21:06 +02:00
Stefan Haller
297a020abf Call getDisplayStrings with a valid range of model indices
It's nicer if clients can rely on the indices being valid, and don't have to
clamp themselves.
2023-08-28 14:21:06 +02:00
Stefan Haller
473d989cde Extract a renderLines function
We'll make some changes to how the display strings are rendered, so it helps to
have this code only once. This also fixes the problem that contexts using
refreshViewportOnChange weren't able to use column alignments so far. We didn't
need this yet, but it's just nice if everything works. :)
2023-08-28 14:21:06 +02:00
Stefan Haller
061bfce835 Change length parameter of getDisplayStrings to endIdx
It's more natural to work with this way, as we will see later in this branch.
2023-08-28 14:21:06 +02:00
Jesse Duffield
996e30e5d9 Add icons for files with .mdx and .svelte file extensions (#2889) 2023-08-28 20:25:03 +10:00
Jesse Duffield
ecd2a14a15 Add install instructions for openSUSE (#2727) 2023-08-28 20:10:49 +10:00
README-bot
8dfa8dc48c Updated README.md 2023-08-28 09:52:42 +00:00
Jesse Duffield
f7c183a429 Add instruction in PR template to start PRs with an imperative (#2967) 2023-08-28 19:52:25 +10:00
Jesse Duffield
473f86fcaa Add instruction in PR template to start PRs with an imperative
This spares me effort when it comes to making release notes.

Yes, sometimes it may be easier to start a message without an imperative e.g. 'When X happens, do Y'
but I don't want to overwhelm the contributor with details.
2023-08-28 19:46:45 +10:00
Jesse Duffield
28353da61b Allow adding a port to webDomain part of services config (#2908) 2023-08-28 19:38:45 +10:00
Jesse Duffield
efd49f07fd Support custom keybindings for confirm discard (#2960) 2023-08-28 19:36:39 +10:00
Jesse Duffield
b8e183acc4 Add installation guide using winget CLI (#2963) 2023-08-28 14:58:56 +10:00
Erick Garcia Godoy
821c4b05fe Add Winget to installation guide 2023-08-27 05:50:12 -03:00
Erick Garcia Godoy
4272d84fa2 Add Winget to installation guide 2023-08-27 05:45:43 -03:00
Mark Skelton
e95505453e Update docs 2023-08-25 08:52:52 -05:00
Mark Skelton
6dc34d19ea Support custom keybindings for confirm discard 2023-08-25 08:50:05 -05:00
Stefan Haller
a670fbb33c Select same commit again after pressing "e" to edit a commit (#2954) 2023-08-24 10:48:07 +02:00
Stefan Haller
98e6c119f5 Select same commit again after pressing "e" to edit a commit
When editing a commit, the index of the current commit can change; for example,
when merge commits are involved, or when working with stacked branches where
"update-ref" commands may be added above the selected commit.

Reselect the current commit after pressing "e"; this requires doing the refresh
blocking on the main thread. (Another option that I considered was to use a
SYNC refresh, and then select the new line with an OnUIThread inside the Then
function. This also works, but results in a very visible lag.)
2023-08-22 14:08:12 +02:00
Stefan Haller
c718a73d0a Call Then function only after everything is done
I'm actually surprised how this could even have worked before.
2023-08-22 14:06:31 +02:00
Stefan Haller
d74c817fd8 Panic when trying to use RefreshOptions.Then with mode ASYNC
This doesn't work, and since it took me a while of debugging to figure this out,
alert other developers earlier when they try to do it.
2023-08-22 14:06:31 +02:00
Stefan Haller
93d19db158 Add assertion to show the problem 2023-08-22 14:06:29 +02:00
Raido Oras
d7b611aa05 Allow port in webDomain for services config values 2023-08-21 14:33:58 +03:00
Jesse Duffield
fc6008fdff fix GitHub Actions warnings (#2950) 2023-08-21 19:27:26 +10:00
kyu08
a65d3119c0 upgrade golangci/golangci-lint-action to v3.7.0 2023-08-21 18:11:33 +09:00
kyu08
51ecf4089b upgrade actions/setup-go to v4 and remove actions/cache for go cache 2023-08-21 18:10:52 +09:00
kyu08
0c0fe8997b upgrade goreleaser/goreleaser-action to v4 2023-08-21 18:09:59 +09:00
kyu08
f86309dd03 upgrade JamesIves/github-sponsors-readme-action to v1.2.2 2023-08-21 18:09:33 +09:00
Stefan Haller
c31fcb7134 Switch to editor from commit message panel (#2881) 2023-08-21 10:12:26 +02:00
Stefan Haller
91ec42f3f8 Add integration test 2023-08-21 10:03:34 +02:00
Stefan Haller
8f628296ad Mention ctrl+o binding in commit message sub title
Only do this when an onSwitchToEditor function is actually provided. For the
"Move patch into new commit" command we don't, because it isn't totally
straightforward in that case.
2023-08-21 10:03:34 +02:00
Stefan Haller
61bd3e8dd2 Add key binding for switching from the commit message panel to an editor
This is useful for when you begin to type the message in lazygit's commit panel,
and then realize that you'd rather use your editor's more powerful editing
capabilities. Pressing <c-o> will take you right there.
2023-08-21 10:03:34 +02:00
Stefan Haller
7263630967 Remove obsolete comment 2023-08-21 10:03:34 +02:00
Jesse Duffield
16711c6f1a Added termux installation [README.md] (#2892) 2023-08-21 18:02:59 +10:00
Jesse Duffield
b2023f10b6 Fix: Update 'zh' to 'zh-CN' in lazygit Language Configuration (#2842) 2023-08-21 17:56:45 +10:00
Stefan Haller
e915488a83 Add gui.scrollOffBehavior config for scrolling list views by half-pages (#2939) 2023-08-21 09:11:03 +02:00
Stefan Haller
b2d629b50a Add scrollOffEnabled config 2023-08-21 09:03:45 +02:00
Stefan Haller
125d4fa9dc Pass UserConfig to checkScrollUp/Down instead of just the scrollOffMargin
This will allow us to add a scrollOffEnabled config and have the functions
respect it without changes to clients.
2023-08-21 08:10:28 +02:00
Stefan Haller
527a1596f3 Add tests for scroll-off margin of zero 2023-08-21 08:10:28 +02:00
Stefan Haller
51d9f70f9e Fix section levels
These appeared as subsections of "Platform Defaults", which doesn't make sense.
2023-08-21 08:10:28 +02:00
Jesse Duffield
83727d48b5 Feature add git flow instructions (#2785) 2023-08-21 15:51:51 +10:00
Bart
8efc175340 Add git flow description in readme 2023-08-21 15:50:54 +10:00
Jesse Duffield
6a6cb25d7e Handle trailing slash in worktree path (#2947) 2023-08-21 13:26:58 +10:00
README-bot
fd782ff568 Updated README.md 2023-08-21 01:26:29 +00:00
Jesse Duffield
dbfb469bad Add Makefile (#2937) 2023-08-21 11:26:15 +10:00
Stefan Haller
888a976fc0 Fix the commit graph display after selection jumps in commits view (#2943) 2023-08-20 08:51:29 +02:00
Stefan Haller
2073730186 Fix the commit graph display after selection jumps in commits view
When navigating in the commits view to a line that is out of view (e.g. by
pressing , or . to scroll by page, or < or > to scroll to the top or bottom),
the commit graph was not correctly highlighted. Fix this by rerendering the
viewport in this case.
2023-08-20 08:46:04 +02:00
Cristian Betivu
7a4a0c85c4 Fix test 2023-08-19 19:12:36 +03:00
Cristian Betivu
382ecb6bfe Add unit test 2023-08-19 19:10:35 +03:00
Cristian Betivu
03694f7502 Fix arg order to asserts 2023-08-19 19:10:25 +03:00
Cristian Betivu
ee308a4994 Clean before convertion? 2023-08-19 18:36:57 +03:00
Cristian Betivu
a2b2336173 Stylistic changes 2023-08-19 18:36:57 +03:00
Cristian Betivu
d7b1deb465 Clean path 2023-08-19 18:36:57 +03:00
Cristian Betivu
dd01639f57 Improve error message 2023-08-19 18:36:57 +03:00
Stefan Haller
525932fbf2 Fix sha colors when rebasing (#2946) 2023-08-19 12:38:00 +02:00
Stefan Haller
b1314349d7 Fix yellow/red coloring while rebasing
It determines the yellow/red status by getting the merge-base between the
current branch and its upstream; while we're rebasing, the current branch is
HEAD, so it tried to get the merge-base between HEAD and HEAD{u}, which doesn't
work. Fix this by passing the name of the checked-out branch separately.
2023-08-19 09:26:27 +02:00
Stefan Haller
9671f549a1 Fix the blue sha color of todo commits while rebasing
This broke with 5d8a85f7e7.
2023-08-19 09:24:00 +02:00
kyu08
a1738a77ae Add Makefile 2023-08-19 00:13:03 +09:00
Jesse Duffield
689deb72bd Add emacs-keybinds for word navigation (#2935) 2023-08-17 09:41:14 +10:00
Ching Pei Yang
84372cfad9 Add emacs-keybinds for word navigation 2023-08-15 12:22:17 +02:00
README-bot
e429415ed4 Updated README.md 2023-08-15 09:49:34 +00:00
Stefan Haller
7402be98b6 Jump to middle of the view when selection leaves the visible area (#2915) 2023-08-15 11:49:20 +02:00
Stefan Haller
341b9725d4 Add ScrollOffMargin user config
When set to a non-zero value, views will scroll when the selection gets this
close to the top or bottom of the view.
2023-08-15 11:40:40 +02:00
Stefan Haller
8f164f7bc5 Stop cycling hunks when reaching the end
Previously, when pressing right-arrow when the cursor is already in the last
hunk, it would jump back to the beginning of that hunk. This can be confusing if
the hunk is long, maybe the start of the hunk is already scrolled off the top of
the window, and then pressing right-arrow actually scrolls *backwards*, which is
counter-intuitive. It's better to do nothing in this case.

Same for left-arrow when the cursor is already in the first hunk, although here
the problem is not so severe (unless diff context was increased by a huge
amount, and the start of the first hunk is scrolled off the bottom of the
window).
2023-08-15 11:40:40 +02:00
Stefan Haller
79c11a0458 If selected line is outside, move it to the middle of the view
Previously, the current line was only moved as much as necessary so that it's in
view again. This had the problem that when jumping downwards from hunk to hunk
with the right-arrow key, only the first line of the new hunk was shown at the
bottom of the window. I prefer to put the selected line in the middle of the
view in this case, so that I can see more of the newly selected hunk.

This has the consequence that when scrolling through the view line by line using
down-arrow, the view jumps by half a screen whenever I reach the bottom. I can
see how some users might be opposed to this change, but I happen to like it too,
because it allows me to see more context of what's ahead.
2023-08-15 11:40:40 +02:00
Stefan Haller
4a4afc4639 Fix typo in comment 2023-08-15 11:40:40 +02:00
Stefan Haller
ebdfd8046a Bump gocui 2023-08-15 11:40:40 +02:00
Jesse Duffield
d99e983236 Add compare-commits demo (#2929) 2023-08-12 17:32:15 +10:00
Jesse Duffield
1c6cfafba7 Add features to table of contents 2023-08-12 17:27:25 +10:00
Jesse Duffield
83d642b74f Add demo for diffing two commits 2023-08-12 17:24:05 +10:00
Jesse Duffield
b1bc437d1b Factor out common config setup functions in demo package 2023-08-12 16:52:40 +10:00
Jesse Duffield
26989ce0ee Show commit mark before showing extra info (#2928) 2023-08-12 16:44:27 +10:00
Jesse Duffield
e6356ce10c Show commit mark before showing extra info
The 'YOU ARE HERE' marking should be shown before we show things like the current tag, otherwise it could be missed
2023-08-12 16:34:04 +10:00
README-bot
b92da0dc54 Updated README.md 2023-08-12 06:19:15 +00:00
Jesse Duffield
70e668bfcf Add more demos (#2927) 2023-08-12 16:18:59 +10:00
Jesse Duffield
8dd517870d Add commit graph demo 2023-08-12 16:16:03 +10:00
Jesse Duffield
f1753f36c8 Add rebase from marked base commit test
This also fixes a bug where after the rebase each commit in the commits view had a tick against it because we hadn't
refreshed the view since the base commit was no longer marked
2023-08-12 16:16:03 +10:00
Jesse Duffield
3ea81d4a6f Add undo demo 2023-08-12 16:15:50 +10:00
Federico
0df5cb1286 Allow deleting remote tags/branches from local tag/branch views (#2738) 2023-08-10 17:39:26 +10:00
Jesse Duffield
c43830b027 Support editing files in existing neovim instance (#2916) 2023-08-10 17:23:58 +10:00
Stefan Haller
08624b8ef7 Fix jumping to the correct line from the staging view (#2919) 2023-08-10 07:27:11 +02:00
Stefan Haller
73b68927af Fix bug in LineNumberOfLine
This fixes a regression that was introduced in 73c7dc9c5d.
2023-08-10 07:22:42 +02:00
Stefan Haller
bf699d3a79 Add test case for LineNumberOfLine()
There's a bug in LineNumberOfLine, but the existing test coverage doesn't catch
it, as the only test case for this was one where oldStart and newStart were the
same for all hunks. Add a test case where newStart is different for one of the
hunks; this demonstrates a bug, where all expected results from index 12 on are
off by one.
2023-08-10 07:22:42 +02:00
README-bot
f2e8d549ba Updated README.md 2023-08-09 22:36:48 +00:00
Jesse Duffield
4ffb6c0fea Show dialogue when attempting to open info link fails (#2899) 2023-08-10 08:36:32 +10:00
Simon Whitaker
54776052a1 If OpenLink errors, show a dialog instead
If the command used by OSCommand.OpenLink fails, lazygit crashes. With this change, if the OpenLink command fails, lazygit just shows a dialog inviting the user to visit the relevant URL.

Fixes #2882
2023-08-09 13:12:40 +01:00
Jesse Duffield
9c5eedf748 use 'suspend' instead of 'editInTerminal' internally
'suspend' is a more appropriate name, especially now that you can choose not to suspend despite
still being in a terminal
2023-08-09 22:03:58 +10:00
Jesse Duffield
ca08956f77 Use soft wrapping in config doc
Looking online I can't find any consensus about whether soft or hard wrap is better.
This post goes into the pros/cons: https://martin-ueding.de/posts/hard-vs-soft-line-wrap/

I find that editing hard-wrapped text is a pain in the ass, and it's hard to enforce
consistency. So I'm switching to soft-wrapping for this doc.
2023-08-09 21:33:12 +10:00
Jesse Duffield
aa74239f05 Add nvim-remote editor preset
This allows us to jump back to the parent neovim process when we want to edit a file, rather than opening a new neovim
process within lazygit.

Arguably this should be the default, but I'm not familiar with the various ways people use lazygit with neovim.
2023-08-09 21:32:53 +10:00
Jesse Duffield
9e7018db8a Honour editInTerminal value when opening a worktree folder
There was no good reason not to do this in the first place.
2023-08-09 21:00:27 +10:00
Jesse Duffield
cdea5b4873 Fix issue where explosion effect was out-of-view (#2909) 2023-08-08 23:07:46 +10:00
Jesse Duffield
4b0432423d Reset origin when clearing view 2023-08-08 22:01:43 +10:00
Jesse Duffield
2607580a09 Add Click() to GuiDriver (#2898) 2023-08-08 17:05:32 +10:00
Jesse Duffield
ebd56bd8d5 Mention JSON schema (#2893) 2023-08-08 08:19:05 +10:00
Simon Whitaker
ed1547e0cb Add a Click() primitive to the integration test library 2023-08-07 15:10:28 +01:00
README-bot
5e388e21c8 Updated README.md 2023-08-07 14:03:45 +00:00
Jesse Duffield
4c89f9fba5 Fix seg-fault when opening submodule in nested folder (#2903) 2023-08-08 00:03:28 +10:00
Jesse Duffield
8e7958f78b Fix seg-fault when opening submodule in nested folder 2023-08-07 23:57:28 +10:00
Jesse Duffield
579791e7bc Fix opening lazygit in a bare repo with specified worktree (#2902) 2023-08-07 22:48:14 +10:00
Jesse Duffield
595e28d335 Support bare worktrees where worktree does not have its own .git file
This was on oversight on my part: I assumed that the --work-tree arg was
always intended for use with linked worktrees which have a .git file
pointing back to the repo.

I'm honestly confused now: seems like there are three kinds of worktrees:
* the main worktree of a non-bare repo
* a linked worktree (with its own gitdir in the repo's worktrees/ dir)
* a random folder which you specify as a worktree with the --work-tree arg

I'm pretty sure the --work-tree arg is only intended to be used with this
third kind or workree
2023-08-07 22:40:53 +10:00
Jesse Duffield
0551f29de9 Test bare repos with dotfile setup 2023-08-07 22:21:23 +10:00
微笑
82b5c20050 Add zh-TW to docs/Config.md
Co-authored-by: Bill ZHANG <36790218+Lutra-Fs@users.noreply.github.com>
2023-08-07 19:52:28 +08:00
Jesse Duffield
ecaf1e9002 Use nerdfont version 3 in demos (#2901) 2023-08-07 21:23:42 +10:00
Jesse Duffield
69ff621494 Use nerdfont version 3
Turns out I was on version 2 when recording these. I've switched
to v3 now.
2023-08-07 21:19:10 +10:00
EmilySeville7cfg
f32fe84c9b feat(doc): better JSON schema usage explanation 2023-08-07 18:27:37 +10:00
Stefan Haller
2ded352f3a Don't run the check-required-label check on master (#2896) 2023-08-07 08:45:48 +02:00
Stefan Haller
c877a8528f Don't run the check-required-label check on master
master doesn't have a label, so CI for master currently always fails.
2023-08-07 08:41:13 +02:00
Stefan Haller
d1754a9490 update worktree icons for NerdFont V3 (#2895) 2023-08-07 08:16:42 +02:00
README-bot
33a96a3dd7 Updated README.md 2023-08-07 06:14:41 +00:00
Stefan Haller
cd889adfa0 Import stefanhaller's tcell fork for real rather than just replacing it (#2888) 2023-08-07 08:14:28 +02:00
Saafo
77447ea6c3 👽️ update worktree icons for NerdFont V3 2023-08-07 05:47:57 +00:00
EmilySeville7cfg
fb05ee369f feat(doc): mention JSON schema 2023-08-07 03:38:30 +10:00
Jothi Prasath
213da4fddd added termux installation 2023-08-06 20:12:11 +05:30
Harshit Tomar
e78a09ebab added svelte and mdx 2023-08-06 20:26:07 +10:00
Stefan Haller
7ccb871a45 Bump gocui
... and import stefanhaller's tcell fork for real rather than just replacing it

This solves the problem that people trying to
"go install github.com/jesseduffield/lazygit@latest" would get the error

go: github.com/jesseduffield/lazygit@latest (in github.com/jesseduffield/lazygit@v0.40.0):
  The go.mod file for the module providing named packages contains one or
  more replace directives. It must not contain directives that would cause
  it to be interpreted differently than if it were the main module.
2023-08-06 12:03:23 +02:00
README-bot
9cc18bd7e6 Updated README.md 2023-08-06 06:29:45 +00:00
Stefan Haller
8e2ecd17a9 Fix README.md typo backkground -> background (#2884) 2023-08-06 08:29:32 +02:00
Mattias Johnson
78676dcff6 Fix README.md typo backkground -> background 2023-08-05 20:09:53 +02:00
README-bot
7847203d6e Updated README.md 2023-08-05 06:14:48 +00:00
Jesse Duffield
af3101c7f2 Fix confirmation view sizing (#2879) 2023-08-05 16:14:34 +10:00
Jesse Duffield
ec7e9f9228 Fix confirmation view sizing
The proper fix is to actually have these two functions share code,
or for views to be able to manage their own heights based on their contents.

But I want to get this out for the sake of a Lazygit Anniversary release.
2023-08-05 16:09:02 +10:00
Jesse Duffield
ab5875c78f Add more demos (#2874) 2023-08-04 09:18:25 +10:00
Jesse Duffield
f6af4c29d4 Add custom patch demo 2023-08-04 09:15:07 +10:00
Jesse Duffield
996ad5bf26 Add worktree demo 2023-08-04 09:14:58 +10:00
Jesse Duffield
096628e366 Add custom command demo 2023-08-04 08:38:15 +10:00
Jesse Duffield
b432fb5efe Add undo/redo demo 2023-08-03 21:02:12 +10:00
Jesse Duffield
c390c9d58e Add filter demo to README 2023-08-03 18:22:30 +10:00
Jesse Duffield
e25403c650 Move features to top of readme (#2867) 2023-08-03 17:25:48 +10:00
Jesse Duffield
5c9a9e777c Move features to top of readme 2023-08-03 17:23:47 +10:00
Jesse Duffield
39d24fdeb7 Add more demos to the README (#2866) 2023-08-03 17:02:40 +10:00
Jesse Duffield
bbb2b32816 Point to new demos 2023-08-03 16:58:11 +10:00
Jesse Duffield
0152639ef0 Add demo for staging lines 2023-08-02 22:32:57 +10:00
Jesse Duffield
c43195efb6 Add demo for amending old commit 2023-08-02 22:32:51 +10:00
Jesse Duffield
17db918cba Add demo for filtering branches 2023-08-02 22:32:51 +10:00
Jesse Duffield
befd7fe63e Support mp4 videos for demos
For all videos but the first video in the readme we want to use mp4 because it's faster, better quality,
smaller, and allows you to play/pause (don't quote me on the smaller part).

HOWEVER: github won't let us reference mp4s stored in our repo from the readme, like it does for gifs
(who knows why). This is annoying because it prevents us from easily re-recording things if the UI
changes. So I've got the logic for recording to mp4 but I'm thinking of sticking to gifs for now
2023-08-02 22:21:25 +10:00
Jesse Duffield
de28391052 Remove file watcher code (#2865) 2023-08-02 22:20:39 +10:00
Jesse Duffield
92f0aa23cc Remove file watcher code
Now that we refresh upon focus, we can scrap this file watching code.
Stefan says few git UIs use file watching, and I understand why: the
reason this code was problematic in the first place is that watching
files is expensive and if you have too many open file handles that
can cause problems.

Importantly: this code that's being removed was _already_ dead.
2023-08-02 21:50:44 +10:00
Jesse Duffield
c8520fbe78 Auto-refresh on window activation (#2854) 2023-08-02 20:42:47 +10:00
Stefan Haller
8ce60662f2 Refresh when the terminal window gets the focus 2023-08-02 11:35:36 +02:00
Stefan Haller
c5acbb6c7c Bump gocui 2023-08-02 11:35:36 +02:00
Stefan Haller
4aca854b59 Point tcell at stefanhaller's fork
This is temporary as long as https://github.com/gdamore/tcell/pull/599 is not
merged. Once that PR is merged, we can revert this.
2023-08-02 11:35:36 +02:00
Jesse Duffield
f7bf125037 Stop worktrees view from stealing the window (#2863) 2023-08-02 09:24:51 +10:00
Jesse Duffield
c92ed07082 Appease linter 2023-08-02 08:32:57 +10:00
Jesse Duffield
df0c3b3ea8 Increase timeout for linter
we've had a timeout issue in CI
2023-08-02 08:32:57 +10:00
Jesse Duffield
280b0429c3 Fix focus issue
When opening lazygit with `lazygit log` the worktrees view was appearing in front of the files view.
This is because it had higher precedence than the files view in the ordered view mapping, and
that was because it originally was in the branches window so it was further down the list.

The reason this didn't cause issues on typical startup is that the files context is activated at the
start so it is brought to the front.
2023-08-02 07:37:40 +10:00
Jesse Duffield
cb22db675a Update README.md 2023-08-02 00:05:04 +10:00
Jesse Duffield
bb21034972 Update README.md 2023-08-01 22:37:53 +10:00
Jesse Duffield
ec5bc93576 Show visual explosion effect when nuking worktree (#2861) 2023-08-01 22:31:29 +10:00
Jesse Duffield
f43fd7af79 Wait in demo after setting caption
This looks nicer than waiting a second and then showing the caption as the action begins
2023-08-01 22:19:04 +10:00
Jesse Duffield
a200fccba9 Add explosion animation when nuking working tree
I've been thinking about this for a while: I think it looks really cool if nuking your working tree
actually results in a nuke animation.

So I've added an opt-out config for it
2023-08-01 22:16:04 +10:00
Jesse Duffield
37dc31b815 Output correct path in demo record script 2023-08-01 22:10:59 +10:00
Jesse Duffield
1712ad08ae Start in fullscreen when passing a git arg
Often we just want to see the desired view in fullscreen so I'm making that the default
2023-08-01 22:10:59 +10:00
README-bot
53f0c1eb4f Updated README.md 2023-08-01 12:03:12 +00:00
Jesse Duffield
c53adbbb84 Update README.md 2023-08-01 22:02:56 +10:00
Jesse Duffield
e932aaaeaf Internationalise logging of commands (#2852) 2023-08-01 10:06:48 +10:00
Jesse Duffield
b44d0c4bde Show loader when rebasing (#2851) 2023-08-01 09:58:11 +10:00
Karl Heitmann
917cfd7586 Adds EditRebaseFromBaseCommit log message to i18n 2023-07-31 19:57:14 -04:00
Karl Heitmann
c7e6a73512 Wraps rebase func with WithWaitingStatus to show loader when rebasing 2023-07-31 19:46:59 -04:00
Karl Heitmann
b7ba06fa5b Moves log related translations into its own Tr.Log. namespace 2023-07-31 19:42:41 -04:00
Karl Heitmann
51e205ce11 Moves hard coded strings for LogCommand to i18n. 2023-07-31 19:35:55 -04:00
README-bot
6984a4f4d4 Updated README.md 2023-07-31 23:12:55 +00:00
Jesse Duffield
4baecec7bf Create demo output dir if it doesn't already exist (#2857) 2023-08-01 09:12:39 +10:00
Jesse Duffield
b262e7f9b8 Create demo output dir if it doesn't already exist 2023-08-01 09:12:23 +10:00
Jesse Duffield
b92c294059 Add automated demo recordings (#2853) 2023-07-31 22:43:36 +10:00
Jesse Duffield
07d03df8df Update README.md 2023-07-31 22:36:40 +10:00
Jesse Duffield
9cc1d65280 Add demo test variant
We're piggybacking on our existing integration test framework to record  demos that we can include in our docs
2023-07-31 22:33:04 +10:00
Jesse Duffield
893c1cab75 Update README.md 2023-07-31 22:19:11 +10:00
Jesse Duffield
25d57350df Update README.md 2023-07-31 22:12:30 +10:00
Jesse Duffield
eb68591396 Update README.md 2023-07-31 20:31:43 +10:00
Stefan Haller
6de9e230a0 Save IgnoreWhitespaceInDiffView in state.yml (#2830) 2023-07-31 11:48:51 +02:00
Stefan Haller
668d29736c Log error when saving app state fails after showing/hiding command log 2023-07-31 11:41:55 +02:00
Stefan Haller
be667682f0 Move IgnoreWhitespaceInDiffView to AppState, and persist it when it changes 2023-07-31 11:41:55 +02:00
Stefan Haller
045bce5dfc Allow force-tagging if tag exists (#2827) 2023-07-31 11:40:40 +02:00
Stefan Haller
3827479643 Show correct keybindings in force-push prompt 2023-07-31 11:38:52 +02:00
Stefan Haller
d41a195ee6 Allow force-tagging if tag exists 2023-07-31 11:38:52 +02:00
Stefan Haller
71d2fd37e2 Rebase onto branch from a marked base commit (#2835) 2023-07-31 08:52:58 +02:00
Stefan Haller
66de981e91 Add a "Mark commit as base commit for rebase" command
This allows to do the equivalent of "git rebase --onto <target> <base>", by
first marking the <base> commit with the new command, and then selecting the
target branch and invoking the usual rebase command there.
2023-07-31 08:41:41 +02:00
Stefan Haller
375451785c Cleanup: remove extra OutsideFilterMode guard
We are in the outsideFilterModeBindings section here; all of these handlers are
wrapped in a OutsideFilterMode guard in a loop below. No need to add one
manually here.
2023-07-31 08:40:47 +02:00
Stefan Haller
a6af31a4cb Visualize local branch heads in commits panel, 2nd approach (#2775) 2023-07-31 08:40:09 +02:00
Stefan Haller
94daf7bddc Add documentation for working with stacked branches 2023-07-31 08:34:01 +02:00
Stefan Haller
4eb73393bb Don't show branch marker for head commit unless updateRefs config is on 2023-07-31 08:34:01 +02:00
Stefan Haller
f5c9764dd2 Don't show branch heads in reflog subcommits
It's tricky to get this right for reflog commits wrt what's the current branch
for each one; so just disable it entirely here, it's probably not something
anybody needs here.
2023-07-31 08:34:01 +02:00
Stefan Haller
6dc25d796b Visualize local branch heads in commits panel
We want to mark all local branch heads with a "*" in the local commits panel, to
make it easier to see how branches are stacked onto each other. In order to not
confuse users with "*" markers that they don't understand, do this only for the
case where users actually use stacked branches; those users are likely not going
to be confused by the display. This means we want to filter out a few branch
heads that shouldn't get the marker: the current branch, any main branch, and
any old branch that has been merged to master already.
2023-07-31 08:34:01 +02:00
Stefan Haller
0c07963a2e Store full sha in branch model
The model will be used for logic, so the full hash is needed there; a shortened
hash of 8 characters might be too short to be unique in very large repos. If
some view wants to display a shortened hash, it should truncate it at
presentation time.
2023-07-31 08:34:01 +02:00
Stefan Haller
092d5dd608 Add CheckedOutBranch to Model struct 2023-07-31 08:34:01 +02:00
Stefan Haller
e9bbd816de Make bisect/basic.go test more concrete
- check out a non-main branch before we start
- add authors to expected commits so that we can see whether the commits show an
  asterisk
- explicitly check what the top line displays after bisecting has started

This shows that the detached head shows an asterisk, which we don't want. We'll
fix that in the next commit.
2023-07-31 08:34:01 +02:00
Stefan Haller
eb6f089a2a Add author short names to commits in test
This allow us to check not only whether a given commit has the branch head
marker, but also that other commits _don't_ have it, which is important.
2023-07-31 08:34:00 +02:00
Stefan Haller
cb240081a8 Improve updateRef test
This test not only tests the correct handling and display of the updateRef
command, but also the visualization of branch heads in the commits panel. Since
we are about to change the behavior here, extend the test so that a master
commit is added (we don't want this to be visualized as a branch head), and then
a stack of two non-main branches. At the end of this branch we only want to
visualize the head commit of the first.
2023-07-31 08:34:00 +02:00
Stefan Haller
9c57444adc Remove the old experimentalShowBranchHeads mechanism and config
We are going to replace it with a better one later in this branch.
2023-07-31 08:34:00 +02:00
Stefan Haller
7b8ebfa27e Fix merge status for update-ref command (#2845) 2023-07-31 08:32:48 +02:00
Stefan Haller
8ab05d6834 Fix merge status of commits when update-ref command is present
Update-ref commands have an empty sha, and strings.HasPrefix returns true when
called with an empty second argument, so whenever an update-ref command is
present in a rebase, all commits from there on down were drawn with a green sha.
2023-07-31 08:28:03 +02:00
Stefan Haller
774df817fd Add tests for setCommitMergedStatuses
The test for update-ref shows demonstrates a problem. See next commit for the
fix.
2023-07-31 08:28:03 +02:00
Stefan Haller
18903a7dde Make setCommitMergedStatuses a non-member function
It doesn't depend on anything in CommitLoader, so it can be free-standing, and
that makes it easier to test (see next commit).
2023-07-31 08:28:03 +02:00
Jesse Duffield
7cfbfb7183 Remove redundant secureexec package (#2847) 2023-07-30 20:04:06 +10:00
Jesse Duffield
975d2bedb6 Remove secureexec package
From the go 1.19 release notes:

Command and LookPath no longer allow results from a PATH search to be found relative to the current directory. This removes a common source of security problems but may also break existing programs that depend on using, say, exec.Command("prog") to run a binary named prog (or, on Windows, prog.exe) in the current directory. See the os/exec package documentation for information about how best to update such programs.
2023-07-30 19:59:51 +10:00
Jesse Duffield
5c78394299 Standardise on using lo for slice functions (#2846) 2023-07-30 18:55:12 +10:00
Jesse Duffield
e33fe37a99 Standardise on using lo for slice functions
We've been sometimes using lo and sometimes using my slices package, and we need to pick one
for consistency. Lo is more extensive and better maintained so we're going with that.

My slices package was a superset of go's own slices package so in some places I've just used
the official one (the methods were just wrappers anyway).

I've also moved the remaining methods into the utils package.
2023-07-30 18:51:23 +10:00
README-bot
ea54cb6e9c Updated README.md 2023-07-30 08:42:37 +00:00
Jesse Duffield
08f0e28e55 Add worktrees view (#2147) 2023-07-30 18:42:25 +10:00
Jesse Duffield
2d4706e96e fix go mod 2023-07-30 18:36:04 +10:00
Jesse Duffield
d30eef69b1 Use double dash for disambuating path in editor templates 2023-07-30 18:35:36 +10:00
Jesse Duffield
91909331b5 Fix flakey worktree tests
In the presentation layer, when showing branches, we'll show worktrees against branches if they're
associated. But there was a race condition: if the worktree model was refreshed after the branches model,
it wouldn't be used in the presentation layer when it came time to render the branches.

A better solution would be to have some way of signalling that a particular context needs to be refreshed
and after all the models are done being refreshed, we then refresh the contexts. This will prevent
double-renders
2023-07-30 18:35:36 +10:00
Jesse Duffield
f31e213edc rename files 2023-07-30 18:35:36 +10:00
Jesse Duffield
7b302d8c29 Write unit tests with the help of afero
Afero is a package that lets you mock out a filesystem with an in-memory filesystem.
It allows us to easily create the files required for a given test without worrying about
a cleanup step or different tests tripping on eachother when run in parallel.

Later on I'll standardise on using afero over the vanilla os package
2023-07-30 18:35:36 +10:00
Jesse Duffield
a1fae41051 Fix bug where worktree view would take over window upon switching branches
When switching worktrees (which we can now do via the branch view) we re-layout the windows and their views.
We had the worktree view ahead of the file view based on the Flatten() method in context.go, because it used
to be associated with the branches panel.
2023-07-30 18:35:24 +10:00
Jesse Duffield
b16bb409fc Use forward-slashes on windows
We want to be using forward slashes everywhere internally, so if we get a path from windows
we should immediately convert it to use forward slashes.

I'm leaving out the recent repos list because that would require a migration
2023-07-30 18:35:24 +10:00
Jesse Duffield
a77d24fdc6 Add section in integration readme about testing against old git versions 2023-07-30 18:35:24 +10:00
Jesse Duffield
eecf07cd12 Add more i18n for worktrees 2023-07-30 18:35:24 +10:00
Jesse Duffield
06be88aef7 Use fields rather than methods on worktrees
I would prefer to use methods to keep things immutable but I'd rather be consistent with the other
models and update them all at once
2023-07-30 18:35:24 +10:00
Jesse Duffield
4c5b1574f1 Centralise logic for obtaining repo paths
There are quite a few paths you might want to get e.g. the repo's path, the worktree's path,
the repo's git dir path, the worktree's git dir path. I want these all obtained once and
then used when needed rather than having to have IO whenever we need them. This is not so
much about reducing time spent on IO as it is about not having to care about errors every time
we want a path.
2023-07-30 18:35:24 +10:00
Jesse Duffield
de57cfd6ff Remove IO logic from presentation code for worktrees
We're doing all the IO in our workers loader method so that we don't need to do any
in our presentation code
2023-07-30 18:35:24 +10:00
Jesse Duffield
2b24c15938 Add test for opening lazygit in the worktree of a bare repo 2023-07-30 18:35:23 +10:00
Jesse Duffield
e874f94cf8 Remove dead function 2023-07-30 18:35:23 +10:00
Jesse Duffield
0a410141ae Fix test by making branches appear deterministically
This fixes pkg/integration/tests/worktree/rebase.go which was failing on old git versions due to a difference in
order of branches that don't have recency values
2023-07-30 18:35:23 +10:00
Jesse Duffield
e356b29b4a Allow entering a submodule by pressing space 2023-07-30 18:35:23 +10:00
Jesse Duffield
bc4ce26cef Allow entering a worktree by pressing enter 2023-07-30 18:35:23 +10:00
Jesse Duffield
ae66f720f5 Update repo switch logic
We now always re-use the state of the repo if we're returning to it, and we always reset the windows to their default tabs.

We reset to default tabs because it's easy to implement. If people want to:
* have tab states be retained when switching
* have tab states specific to the current repo retained when switching back

Then we'll need to revisit this
2023-07-30 18:35:23 +10:00
Jesse Duffield
9c15ba0c0b Add test for retained context focus when switching worktrees 2023-07-30 18:35:23 +10:00
Jesse Duffield
b3060065d9 Support fastforwarding worktree 2023-07-30 18:35:23 +10:00
Jesse Duffield
a313b16704 Add more worktree tests 2023-07-30 18:35:23 +10:00
Jesse Duffield
b93b9dae88 Add worktree tests for removing/detaching 2023-07-30 18:35:23 +10:00
Jesse Duffield
277142fc4b Add worktree integration tests 2023-07-30 18:35:23 +10:00
Jesse Duffield
18a508b29c Update cheatsheets 2023-07-30 18:35:23 +10:00
Jesse Duffield
cdfad864ae Remove worktree version guards
Our min required git version is 2.20 so there's no need to add guards
for worktrees because they were added in 2.5
2023-07-30 18:35:23 +10:00
Jesse Duffield
fb4453c18a Fix unit tests 2023-07-30 18:35:23 +10:00
Jesse Duffield
b5ff55e538 Show loader when switching worktrees 2023-07-30 18:35:23 +10:00
Jesse Duffield
81a9133261 Support older versions of git when fetching worktrees
Older versions of git don't support the -z flag in `git worktree list`.
So we're using newlines.

Also, we're not raising an error upon error because that triggers another refresh,
which gets us into an infinite loop
2023-07-30 18:35:23 +10:00
Jesse Duffield
ca6f9c4155 Fix tests
Going and fixing up some submodule tests which were broken by bad assumptions with worktree code
2023-07-30 18:35:23 +10:00
Jesse Duffield
7569180cac Fix tests
We now change directories to the repo on startup so we don't need to determine the test path in some special way
2023-07-30 18:35:23 +10:00
Jesse Duffield
eeec373728 Safer fetching of linked worktree paths 2023-07-30 18:35:23 +10:00
Jesse Duffield
0604e43813 Move worktrees tab to files window 2023-07-30 18:35:23 +10:00
Jesse Duffield
27ade502ee Change directory to worktree if given as an argument
Previously we used an env var for this and it's not clear to me how that worked but
with this PR current directory = worktree directory
2023-07-30 18:35:23 +10:00
Jesse Duffield
3a7468ecac Support opening worktree in editor 2023-07-30 18:35:23 +10:00
Jesse Duffield
7b05dacb98 Properly render worktrees in files panel 2023-07-30 18:35:22 +10:00
Jesse Duffield
b73efb2c22 Better logic for knowing which repo we're in 2023-07-30 18:35:22 +10:00
Jesse Duffield
a06a5cadee Only show worktree in status panel if not the main worktree and worktrees are supported 2023-07-30 18:35:22 +10:00
Jesse Duffield
3cd2d6fa5c Hide worktree functionality on old git versions 2023-07-30 18:35:22 +10:00
Jesse Duffield
ec839e9e96 Associate branches with worktrees even when mid-rebase 2023-07-30 18:35:22 +10:00
Jesse Duffield
6f2f9f6677 Assume that the base of a worktree can be checked out 2023-07-30 18:35:22 +10:00
Jesse Duffield
2082fdf84a i18n for worktrees 2023-07-30 18:35:22 +10:00
Jesse Duffield
894485190b Don't quit on error 2023-07-30 18:35:22 +10:00
Jesse Duffield
87b2455dbb Allow opening worktree in editor
This does the job but I think we need yet another editor command for opening a directory in a new window.
2023-07-30 18:35:22 +10:00
Jesse Duffield
2e68967e02 Show base ref suggestions when creating worktree 2023-07-30 18:35:22 +10:00
Jesse Duffield
71422a8549 Refresh work trees when discarding file changes
We do this because we may be deleting a worktree folder so we'll need to show that in the worktrees view
2023-07-30 18:35:22 +10:00
Jesse Duffield
9c69a5df69 Checkout worktree when creating from worktree view 2023-07-30 18:35:22 +10:00
Jesse Duffield
9b24995990 Use 'M' for months in branches panel 2023-07-30 18:35:22 +10:00
Jesse Duffield
142f06357f Fix filtering logic in worktrees view 2023-07-30 18:35:22 +10:00
Jesse Duffield
18ea68c23a Support creating worktrees from refs 2023-07-30 18:35:22 +10:00
Jesse Duffield
4b2622d93b Fix wording 2023-07-30 18:35:22 +10:00
Jesse Duffield
ae0193698e Log when directory is changed 2023-07-30 18:35:22 +10:00
Jesse Duffield
6b4a638415 Handle deleting branch attached to worktree 2023-07-30 18:35:22 +10:00
Jesse Duffield
4b3c9f5b35 Update wording 2023-07-30 18:35:22 +10:00
Jesse Duffield
6c69549ced Don't touch repo stack when switching worktrees
We shouldn't touch this cos we're doing a lateral move
2023-07-30 18:35:22 +10:00
Jesse Duffield
5868750aba Move status panel presentation logic into presentation package 2023-07-30 18:35:22 +10:00
Jesse Duffield
ab3052f642 Land in the same panel when switching to a worktree 2023-07-30 18:35:22 +10:00
Jesse Duffield
53f4ccb809 Move current worktree to top of list 2023-07-30 18:35:22 +10:00
Jesse Duffield
077ae99438 Prompt to switch to worktree when branch is checked out by other worktree 2023-07-30 18:35:22 +10:00
Jesse Duffield
fe8adf9eb8 Use git lingo 2023-07-30 18:35:22 +10:00
Jesse Duffield
c713d550c0 Improve name handling 2023-07-30 18:35:22 +10:00
Jesse Duffield
d19d89ea9d Use sentence case 2023-07-30 18:35:22 +10:00
Jesse Duffield
e8ec41fb0f Refactor 2023-07-30 18:35:22 +10:00
Jesse Duffield
7682ec029b Update worktree model 2023-07-30 18:35:22 +10:00
Jesse Duffield
03f726038e Alert when attempting to enter the current worktree 2023-07-30 18:35:21 +10:00
Jesse Duffield
796945aad0 Remove comment 2023-07-30 18:35:21 +10:00
Joel Baranick
db02c13bf6 Address PR comments 2023-07-30 18:35:21 +10:00
Joel Baranick
1ce9a87544 Basic support for adding a worktree 2023-07-30 18:35:21 +10:00
Joel Baranick
35e6e6347a Put all worktree i18n strings together
Use tabwriter to align worktree panel contents
2023-07-30 18:35:21 +10:00
Joel Baranick
54708233ac Improve worktree panel 2023-07-30 18:35:21 +10:00
Joel Baranick
c679fd1924 Style missing worktree as red and display better error when trying to switch to them
Use a broken link icon for missing worktrees
2023-07-30 18:35:21 +10:00
Joel Baranick
9a79154d05 Hide worktrees in the worktree panel if they point at a non-existing filesystem location.
Remove unneeded check when filtering out branches from non-current worktrees from the branch panel.
Add link icon for linked worktrees
2023-07-30 18:35:21 +10:00
Joel Baranick
60872c91e6 Update status to differentiate the main vs linked worktrees 2023-07-30 18:35:21 +10:00
Joel Baranick
afc4aedd4f Support for deleting a worktree 2023-07-30 18:35:21 +10:00
Joel Baranick
f8ba899b87 Initial addition of support for worktrees 2023-07-30 18:35:21 +10:00
Stefan Haller
52447e5d46 When bisecting, always mark the current commit as good/bad, not the selected (#2837) 2023-07-29 14:56:14 +02:00
Stefan Haller
6794149ec8 When bisecting, always mark the current commit as good/bad, not the selected
For marking as good or bad, the current commit is pretty much always the one you
want to mark, not the selected. It's different for skipping; sometimes you know
already that a certain commit doesn't compile, for example, so you might
navigate there and mark it as skipped. So in the case that the current commit is
not the selected one, we now offer two separate menu entries for skipping, one
for the current commit and one for the selected.
2023-07-29 14:44:00 +02:00
Stefan Haller
a4772ae606 Add bisect menu entry that lets you choose bisect terms (#2838) 2023-07-29 12:02:22 +02:00
Stefan Haller
f30e09856c Add bisect menu entry that lets you choose bisect terms
This can be useful if you want to find the commit that fixed a bug (you'd use
"broken/fixed" instead of "good/bad" in this case), or if you want to find the
commit that brought a big performance improvement (use "slow/fast"). It's pretty
mind-bending to have to use "good/bad" in these cases, and swap their meanings
in your head.

Thankfully, lazygit already had support for using custom terms during the bisect
(for the case that a bisect was started on the command-line, I suppose), so all
that's needed is adding a way to specify them in lazygit.
2023-07-29 11:59:58 +02:00
Stefan Haller
9b7f978e3e Fix the x/exp dependency (#2844) 2023-07-29 11:59:04 +02:00
Jesse Duffield
f17417219a feat: add os.copyToClipboardCmd to allow for a custom command #1055 (#2784) 2023-07-29 19:35:52 +10:00
Red S
d7f84aed8a feat: add os.copyToClipboardCmd to allow for a custom command
Issue #1055

test: CopyPatchToClipboard (temporary commit for review)
2023-07-29 19:09:59 +10:00
Stefan Haller
deecbadda9 Fix the x/exp dependency
We started to use it directly in 429225da80.
2023-07-29 10:01:41 +02:00
微笑
1431ffcebf Corrected 'zh' to 'zh-CN' in lazygit docs for proper localization 2023-07-29 12:07:40 +08:00
README-bot
1db1fee03a Updated README.md 2023-07-29 02:39:15 +00:00
Jesse Duffield
2f0116170d Faster refresh (#2841) 2023-07-29 12:39:00 +10:00
Jesse Duffield
429225da80 Support random order of command execution in unit tests
Now that we run code concurrently in our loaders, we need to handle that in our tests.
We could enforce a deterministic ordering by mocking waitgroup or something like that,
but I think it's fine to let our tests handle some randomness given that prod itself
will have that randomness.

I've removed the patch test file because it was clunky, not providing much value, and
it would have been hard to refactor to the new pattern
2023-07-29 12:36:17 +10:00
Jesse Duffield
39b77c0fca Have staging refresh wait for files to refresh first 2023-07-29 10:20:15 +10:00
Jesse Duffield
63e5790410 Speed up refresh using concurrency and wait groups
Previously our synchronous refreshes took far longer because nothing
was happening concurrently. We now run refresh functions concurrently
and use a wait group to ensure they're all done before returning
2023-07-29 10:04:11 +10:00
Jesse Duffield
272e021c08 Refactor reflog commit loader
No functional changes
2023-07-29 10:04:11 +10:00
Jesse Duffield
862ebd25cb Speed up remote loader
We're:
* using concurrency with wait groups
* avoiding regex
* processing lines of input as they come rather than storing everything in one string
* avoiding an inner loop by creating a mapping of remote names to branches
2023-07-29 10:04:11 +10:00
Jesse Duffield
5d8a85f7e7 Use wait groups to speed up commit loading
The speedup is most noticeable on first load, when we haven't yet fetched out main branches.
I saw a speedup from 105ms to 60ms. On subsequent loads the gain is more modest;
54ms to 40ms
2023-07-29 10:04:11 +10:00
Jesse Duffield
5f30ccfbc3 Log duration of post-refresh-update call
Notably, the reflog view is taking ages here because it's got a
few thousand lines to write to the view.

In future we should only populate the view's viewport.
2023-07-29 09:39:22 +10:00
Jesse Duffield
71cab4fadc Log duration of commands
This will help us diagnose performance issues
2023-07-29 09:39:22 +10:00
Jesse Duffield
09ce430240 Log duration of refresh 2023-07-29 09:39:10 +10:00
Stefan Haller
6be9109aaa Show error when trying to open patch menu with an empty patch (#2829) 2023-07-26 14:34:58 +02:00
Stefan Haller
67a7293e79 Show error when trying to open patch menu with an empty patch 2023-07-26 14:27:18 +02:00
Jesse Duffield
decb055df9 Fix issue where using null to un-map a keybinding was ignored (#2832) 2023-07-26 20:26:51 +10:00
hatredholder
75674d819c bring back yaml library fork 2023-07-26 12:50:39 +03:00
README-bot
35c430c8c9 Updated README.md 2023-07-24 11:15:05 +00:00
Jesse Duffield
94426de533 Fix infinite wait on push/pull on windows (#2821) 2023-07-24 21:14:51 +10:00
Jesse Duffield
c4e27bf96c Revert "Fix flakey pull_merge_conflict test"
This reverts commit 90613056ce, or the part that removed
a goroutine at least.

Reverting because this has caused an infinite wait for push/pull on windows.
We'll need to find out why that happens separately
2023-07-24 21:12:03 +10:00
Jesse Duffield
57bb1aa698 Support typing special characters like '[' on non-english keyboards (#2818) 2023-07-24 10:47:15 +10:00
Jesse Duffield
02270e9ccd README.md: Add Gentoo installation documentation (#2811) 2023-07-24 09:48:51 +10:00
Fabio Coatti
1199c18b53 README.md: Add Gentoo installation documentation 2023-07-23 16:43:26 +02:00
Arnaud MASSERANN
4f807eeb19 Could not type special characters on non-english keyboards
On german/french/spanish keyboards, typing [ requires modifier
keys like AltGr, so the `mod==0` condition is wrong.

Fixes #2573

ch != 0 is useless because IsPrint is implemented this way:
	if uint32(r) <= MaxLatin1 {
		return properties[uint8(r)]&128 != 0
	}
with properties[0] set to 1 (so, bit 7 not set)
-> 0 is not printable.
2023-07-23 14:33:50 +02:00
Stefan Haller
7c44b76477 Prompt for commit message when moving a custom patch to a new commit (#2800) 2023-07-23 14:00:41 +02:00
Stefan Haller
c21633b1be Prompt for commit message when moving a custom patch to a new commit 2023-07-23 13:55:48 +02:00
Jesse Duffield
1b05ba252c Fix crash caused by simultaneous read/write of scanner buffer (#2813) 2023-07-23 13:55:51 +10:00
Jesse Duffield
28474b08ee Fix crash caused by simultaneous read/write of scanner buffer 2023-07-23 13:17:37 +10:00
Jesse Duffield
6f13b42279 Better word wrap (#2812) 2023-07-23 11:46:52 +10:00
Jesse Duffield
8637587b82 Better word wrap
Word wrapping has been pretty bad so far so let's fix that.
2023-07-23 11:43:10 +10:00
Jesse Duffield
f581dc4a56 Update README.md 2023-07-22 15:31:03 +10:00
Jesse Duffield
693e9fc152 Update README.md
Removing unneeded go docs tag
2023-07-22 15:14:18 +10:00
Jesse Duffield
c595833883 Better tag creation UX (#2809) 2023-07-22 14:44:18 +10:00
Jesse Duffield
7807b40322 Better tag creation UX
Previously we used a single-line prompt for a tag annotation. Now we're using the commit message
prompt.

I've had to update other uses of that prompt to allow the summary and description labels to
be passed in
2023-07-22 14:36:35 +10:00
Jesse Duffield
b284970bac Use fuzzy search when filtering a view (#2808) 2023-07-22 13:17:46 +10:00
Jesse Duffield
b46623ebef Use fuzzy search when filtering a view
This adds fuzzy filtering instead of exact match filtering, which is more forgiving of typos
and allows more efficiency.
2023-07-22 13:14:29 +10:00
Jesse Duffield
084c0a19bc Include more commit authors in author suggestions (#2807) 2023-07-22 11:00:38 +10:00
Jesse Duffield
3cee37388c Keep track of authors across local commits and branch commits for suggestions
Previously, we would only show the authors based on local commits, but sometimes you want to set a commit author
to that of a commit on another branch. Now, so long as you've viewed the branch's commits, the author will appear
as a suggestion.
2023-07-22 10:47:04 +10:00
Andrew Savinykh
a7969aef2c Fix rendering to main view on windows 2023-07-22 09:14:05 +10:00
Jesse Duffield
39c900c7e7 Fix goreleaser 2023-07-21 09:03:47 +10:00
Jesse Duffield
6e247c1583 Only apply right-alignment on first column of keybindings menu (#2801) 2023-07-20 21:27:01 +10:00
Jesse Duffield
87bf1dbc7f Only apply right-alignment on first column of keybindings menu
Previously we applied a right-align on the first column of _all_ menus, even though we really
only intended for it to be on the first column of the keybindings menu (that you get from pressing
'?')
2023-07-20 21:23:46 +10:00
Jesse Duffield
1f920ae6ba Fix crash on empty menu (#2799) 2023-07-20 21:17:14 +10:00
Jesse Duffield
932e01b41a Add test for crashing on empty menu 2023-07-20 21:08:56 +10:00
Jesse Duffield
373f24c80f Fix crash on empty menu
When a menu is empty (e.g. due to filtering) we shouldn't crash on focus or selection
2023-07-20 21:05:52 +10:00
Jesse Duffield
a548b289ef Add missing label to label checker (#2798) 2023-07-20 17:33:10 +10:00
Jesse Duffield
b168fc8cdd Add missing label to label checker 2023-07-20 17:31:40 +10:00
Jesse Duffield
94845dcf98 Update release notes config and add CI check (#2797) 2023-07-20 17:19:49 +10:00
Jesse Duffield
1af6dff64e Update release notes config and add CI check 2023-07-20 17:15:10 +10:00
Jesse Duffield
72de4f436e Add release config for generating release notes (#2793) 2023-07-19 23:38:04 +10:00
Pavel Dostál
1a2a301aa2 Add instructions for openSUSE 2023-06-12 08:21:34 +02:00
1501 changed files with 138573 additions and 37288 deletions

7
.codespellrc Normal file
View File

@@ -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

4
.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
root = true
[*.go]
indent_style = tab

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
*.go text
*.md text eol=lf
*.json text eol=lf

View File

@@ -2,9 +2,15 @@
- **Please check if the PR fulfills these requirements**
* [ ] Cheatsheets are up-to-date (run `go run scripts/cheatsheet/main.go generate`)
* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [ ] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] 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))
* [ ] 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
<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for examples
-->

7
.github/release.yml vendored
View File

@@ -8,10 +8,10 @@ changelog:
- feature
- title: Enhancements 🔥
labels:
- improvement
- enhancement
- title: Fixes 🔧
labels:
- bugfix
- bug
- title: Maintenance ⚙️
labels:
- maintenance
@@ -21,6 +21,9 @@ changelog:
- title: I18n 🌎
labels:
- i18n
- title: Performance Improvements 📊
labels:
- performance
- title: Other Changes
labels:
- "*"

View File

@@ -3,22 +3,26 @@ name: Continuous Delivery
on:
push:
tags:
- 'v*'
- "v*"
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Unshallow repo
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
go-version: 1.22.x
- name: Run goreleaser
uses: goreleaser/goreleaser-action@v1
uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: v1.17.2
args: release --clean
env:
GITHUB_TOKEN: ${{secrets.GITHUB_API_TOKEN}}
homebrew:

View File

@@ -1,7 +1,7 @@
name: Continuous Integration
env:
GO_VERSION: 1.18
GO_VERSION: 1.22
on:
push:
@@ -28,24 +28,22 @@ jobs:
GOFLAGS: -mod=vendor
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
- name: Cache build
uses: actions/cache@v3
with:
path: |
${{matrix.cache_path}}
~/go/pkg/mod
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
restore-keys: |
${{runner.os}}-go-
go-version: 1.22.x
- name: Test code
# we're passing -short so that we skip the integration tests, which will be run in parallel below
run: |
go test ./... -short
mkdir -p /tmp/code_coverage
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
- name: Upload code coverage artifacts
uses: actions/upload-artifact@v4
with:
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
path: /tmp/code_coverage
integration-tests:
strategy:
fail-fast: false
@@ -63,11 +61,11 @@ jobs:
GOFLAGS: -mod=vendor
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Restore Git cache
if: matrix.git-version != 'latest'
id: cache-git-restore
uses: actions/cache/restore@v3
uses: actions/cache/restore@v4
with:
path: ~/git-${{matrix.git-version}}
key: ${{runner.os}}-git-${{matrix.git-version}}
@@ -84,28 +82,28 @@ jobs:
run: sudo make -C "$HOME/git-${{matrix.git-version}}" -j install
- name: Save Git cache
if: steps.cache-git-restore.outputs.cache-hit != 'true' && matrix.git-version != 'latest'
uses: actions/cache/save@v3
uses: actions/cache/save@v4
with:
path: ~/git-${{matrix.git-version}}
key: ${{runner.os}}-git-${{matrix.git-version}}
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
- name: Cache build
uses: actions/cache@v1
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
restore-keys: |
${{runner.os}}-go-
go-version: 1.22.x
- name: Print git version
run: git --version
- name: Test code
env:
# See https://go.dev/blog/integration-test-coverage
LAZYGIT_GOCOVERDIR: /tmp/code_coverage
run: |
mkdir -p /tmp/code_coverage
./scripts/run_integration_tests.sh
- name: Upload code coverage artifacts
uses: actions/upload-artifact@v4
with:
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
path: /tmp/code_coverage
build:
runs-on: ubuntu-latest
env:
@@ -113,20 +111,11 @@ jobs:
GOARCH: amd64
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
- name: Cache build
uses: actions/cache@v1
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-build
restore-keys: |
${{runner.os}}-go-
go-version: 1.22.x
- name: Build linux binary
run: |
GOOS=linux go build
@@ -149,31 +138,23 @@ jobs:
GOARCH: amd64
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
- name: Cache build
uses: actions/cache@v1
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-build
restore-keys: |
${{runner.os}}-go-
- name: Check Cheatsheet
run: |
go run scripts/cheatsheet/main.go check
go-version: 1.22.x
- name: Check Vendor Directory
# ensure our vendor directory matches up with our go modules
run: |
go mod vendor && git diff --exit-code || (echo "Unexpected change to vendor directory. Run 'go mod vendor' locally and commit the changes" && exit 1)
- name: Check Integration Test List
# ensure our integration test list is up to date
- name: Check go.mod file
# ensure our go.mod file is clean
run: |
go generate pkg/integration/tests/tests.go && git diff --exit-code || (echo "Integration test list not up to date. Run 'go generate pkg/integration/tests/tests.go' locally and commit the changes" && exit 1)
go mod tidy && git diff --exit-code || (echo "go.mod file is not clean. Run 'go mod tidy' locally and commit the changes" && exit 1)
- name: Check All Auto-Generated Files
# ensure all our auto-generated files are up to date
run: |
go generate ./... && git diff --quiet || (git status -s; echo "Auto-generated files not up to date. Run 'go generate ./...' locally and commit the changes" && exit 1)
shell: bash # needed so that we get "-o pipefail"
- name: Check Filenames
run: scripts/check_filenames.sh
@@ -183,24 +164,77 @@ jobs:
GOFLAGS: -mod=vendor
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v1
uses: actions/setup-go@v5
with:
go-version: 1.18.x
- name: Cache build
uses: actions/cache@v1
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
restore-keys: |
${{runner.os}}-go-
go-version: 1.22.x
- name: Lint
uses: golangci/golangci-lint-action@v3.1.0
uses: golangci/golangci-lint-action@v6.1.0
with:
version: latest
version: v1.60
- name: errors
run: golangci-lint run
if: ${{ failure() }}
check-required-label:
runs-on: ubuntu-latest
if: github.ref != 'refs/heads/master'
steps:
- uses: mheap/github-action-required-labels@v5
with:
mode: exactly
count: 1
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n, performance"
upload-coverage:
# List all jobs that produce coverage files
needs: [unit-tests, integration-tests]
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
- name: Download all coverage artifacts
uses: actions/download-artifact@v4
with:
path: /tmp/code_coverage
- name: Combine coverage files
run: |
# Find all directories in /tmp/code_coverage and create a comma-separated list
COVERAGE_DIRS=$(find /tmp/code_coverage -mindepth 1 -maxdepth 1 -type d -printf '/tmp/code_coverage/%f,' | sed 's/,$//')
echo "Coverage directories: $COVERAGE_DIRS"
# Run the combine command with the generated list
go tool covdata textfmt -i=$COVERAGE_DIRS -o coverage.out
echo "Combined coverage:"
go tool cover -func coverage.out | tail -1 | awk '{print $3}'
- name: Upload to Codacy
run: |
CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
--force-coverage-parser go -r coverage.out
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 }}

25
.github/workflows/codespell.yml vendored Normal file
View File

@@ -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

77
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
name: Automated Release
on:
schedule:
# Runs at 2:00 AM UTC on the first Saturday of every month
- cron: '0 2 * * 6'
workflow_dispatch: # Allow manual triggering of the workflow
jobs:
check-and-release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
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")
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
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 }}"
new_minor=$((minor + 1))
new_tag="$major.$new_minor.0"
echo "New tag: $new_tag"
echo "new_tag=$new_tag" >> $GITHUB_ENV
# This will trigger a deploy via .github/workflows/cd.yml
- name: Push New 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_TOKEN }}

View File

@@ -9,20 +9,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Generate Sponsors 💖
uses: JamesIves/github-sponsors-readme-action@v1.0.8
uses: JamesIves/github-sponsors-readme-action@v1.2.2
with:
token: ${{ secrets.SPONSORS_TOKEN }}
file: 'README.md'
file: "README.md"
if: ${{ github.repository == 'jesseduffield/lazygit' }}
- name: Commit and push if changed
run: |-
git diff
git config --global user.email "actions@users.noreply.github.com"
git config --global user.name "README-bot"
git add README.md
git commit -m "Updated README.md" || exit 0
git push
- name: Create Pull Request 🚀
uses: peter-evans/create-pull-request@v6
with:
commit-message: "README.md: Update Sponsors"
title: "README.md: Update Sponsors"
author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
labels: "ignore-for-release"
delete-branch: true

12
.gitignore vendored
View File

@@ -5,9 +5,7 @@
# Hidden
.*
# TODO
TODO.*
!.codespellrc
# Notes
*.notes
@@ -22,6 +20,7 @@ lazygit.exe
# Exceptions
!.gitignore
!.gitattributes
!.goreleaser.yml
!.golangci.yml
!.circleci/
@@ -35,7 +34,12 @@ lazygit.exe
test/git_server/data
test/results/**
test/_results/**
oryxBuildBinary
__debug_bin
.worktrees
demo/output/*
coverage.out

View File

@@ -1,29 +1,36 @@
linters:
disable:
- structcheck # gives false positives
enable:
- gofumpt
- thelper
- goimports
- tparallel
- wastedassign
- exportloopref
- unparam
- prealloc
- unconvert
- exhaustive
- makezero
- nakedret
# - goconst # TODO: enable and fix issues
- copyloopvar
fast: false
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:
default-signifies-exhaustive: true
staticcheck:
# SA1019 is for checking that we're not using fields marked as deprecated
# in a comment. It decides this in a loose way so I'm silencing it. Also because
# it's tripping on our own structs.
checks: ["all", "-SA1019"]
nakedret:
# the gods will judge me but I just don't like naked returns at all
max-func-lines: 0
run:
go: 1.18
go: '1.22'
timeout: 10m

View File

@@ -12,7 +12,7 @@ builds:
- amd64
- arm
- arm64
- 386
- '386'
# Default is `-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}`.
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.buildSource=binaryRelease

45
.vscode/launch.json vendored
View File

@@ -7,11 +7,12 @@
"request": "launch",
"mode": "auto",
"program": "main.go",
"args": ["--debug", "--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"],
"args": [
"--debug",
"--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"
],
"hideSystemGoroutines": true,
"console": "integratedTerminal",
"presentation": {
"hidden": true
}
},
{
"name": "Tail Lazygit logs",
@@ -19,17 +20,41 @@
"request": "launch",
"mode": "auto",
"program": "main.go",
"args": ["--logs", "--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"],
"args": [
"--logs",
"--use-config-file=${workspaceFolder}/.vscode/debugger_config.yml"
],
"console": "integratedTerminal",
"presentation": {
"hidden": true
}
}
},
{
"name": "Attach to a running Lazygit",
"type": "go",
"request": "attach",
"mode": "local",
"processId": "lazygit",
"hideSystemGoroutines": true,
"console": "integratedTerminal",
},
{
// To use this, first start an integration test with the "cli" runner and
// use the -debug option; e.g.
// $ make integration-test-cli -- -debug tag/reset.go
"name": "Attach to integration test runner",
"type": "go",
"request": "attach",
"mode": "local",
"processId": "test_lazygit",
"hideSystemGoroutines": true,
"console": "integratedTerminal",
},
],
"compounds": [
{
"name": "Run with logs",
"configurations": ["Tail Lazygit logs", "Debug Lazygit"],
"configurations": [
"Tail Lazygit logs",
"Debug Lazygit"
],
"stopAll": true
}
]

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"gopls": {
"formatting.gofumpt": true,
},
}

View File

@@ -10,6 +10,19 @@ 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.
## 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
[This doc](./docs/dev/Codebase_Guide.md) explains:
* what the different packages in the codebase are for
* where important files live
* important concepts in the code
* how the event loop works
* other useful information
## All code changes happen through Pull Requests
Pull requests are the best way to propose changes to the codebase. We actively
@@ -21,6 +34,8 @@ welcome your pull requests:
4. Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
5. Issue that pull request!
Please do not raise pull request from your fork's master branch: make a feature branch instead. Lazygit maintainers will sometimes push changes to your branch when reviewing a PR and we often can't do this if you use your master branch.
If you've never written Go in your life, then join the club! Lazygit was the maintainer's first Go program, and most contributors have never used Go before. Go is widely considered an easy-to-learn language, so if you're looking for an open source project to gain dev experience, you've come to the right place.
## Running in a VSCode dev container
@@ -97,6 +112,10 @@ To run gofumpt from your terminal go:
go install mvdan.cc/gofumpt@latest && gofumpt -l -w .
```
## Programming Font
Lazygit supports [Nerd Fonts](https://www.nerdfonts.com) to render certain icons. Sometimes we use some of these icons verbatim in string literals in the code (mainly in tests), so you need to set your development environment to use a nerd font to see these.
## Internationalisation
Boy that's a hard word to spell. Anyway, lazygit is translated into several languages within the pkg/i18n package. If you need to render text to the user, you should add a new field to the TranslationSet struct in `pkg/i18n/english.go` and add the actual content within the `EnglishTranslationSet()` method in the same file. Then you can access via `gui.Tr.YourNewText` (or `self.c.Tr.YourNewText`, etc). Although it is appreciated if you translate the text into other languages, it's not expected of you (google translate will likely do a bad job anyway!).
@@ -139,31 +158,7 @@ If you want to trigger a debug session from VSCode, you can use the following sn
## 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`
```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.
If you want to investigate what's contributing to CPU or memory usage, see [this separate document](docs/dev/Profiling.md).
## Testing

View File

@@ -2,14 +2,14 @@
# docker build -t lazygit .
# docker run -it lazygit:latest /bin/sh
FROM golang:1.18 as build
FROM golang:1.22 as build
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY go.mod go.sum ./
RUN go mod download
COPY . .
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
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY --from=build /go/src/github.com/jesseduffield/lazygit ./

72
Makefile Normal file
View File

@@ -0,0 +1,72 @@
.PHONY: all
all: build
.PHONY: build
build:
go build -gcflags='all=-N -l'
.PHONY: install
install:
go install
.PHONY: run
run: build
./lazygit
# Run `make run-debug` in one terminal tab and `make print-log` in another to view the program and its log output side by side
.PHONY: run-debug
run-debug:
go run main.go -debug
.PHONY: print-log
print-log:
go run main.go --logs
.PHONY: unit-test
unit-test:
go test ./... -short
.PHONY: test
test: unit-test integration-test-all
# Generate all our auto-generated files (test list, cheatsheets, maybe other things in the future)
.PHONY: generate
generate:
go generate ./...
.PHONY: format
format:
gofumpt -l -w .
.PHONY: lint
lint:
golangci-lint run
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
.PHONY: integration-test-tui
integration-test-tui:
go run cmd/integration_test/main.go tui $(filter-out $@,$(MAKECMDGOALS))
.PHONY: integration-test-cli
integration-test-cli:
go run cmd/integration_test/main.go cli $(filter-out $@,$(MAKECMDGOALS))
.PHONY: integration-test-all
integration-test-all:
go test pkg/integration/clients/*.go
.PHONY: bump-gocui
bump-gocui:
scripts/bump_gocui.sh
.PHONY: bump-lazycore
bump-lazycore:
scripts/bump_lazycore.sh
.PHONY: record-demo
record-demo:
demo/record_demo.sh $(filter-out $@,$(MAKECMDGOALS))
.PHONY: vendor
vendor:
go mod vendor && go mod tidy

286
README.md

File diff suppressed because one or more lines are too long

104
VISION.md Normal file
View File

@@ -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.

26
cmd/i18n/main.go Normal file
View File

@@ -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)
}
}

View File

@@ -16,7 +16,7 @@ Usage:
> go run cmd/integration_test/main.go cli [--slow] [--sandbox] <test1> <test2> ...
If you pass no test names, it runs all tests
Accepted environment variables:
KEY_PRESS_DELAY (e.g. 200): the number of milliseconds to wait between keypresses
INPUT_DELAY (e.g. 200): the number of milliseconds to wait between keypresses or mouse clicks
TUI mode:
> go run cmd/integration_test/main.go tui
@@ -26,6 +26,29 @@ Usage:
> go run cmd/integration_test/main.go help
`
type flagInfo struct {
name string // name of the flag; can be used with "-" or "--"
flag *bool // a pointer to the variable that should be set to true when this flag is passed
}
// Takes the args that you want to parse (excluding the program name and any
// subcommands), and returns the remaining args with the flags removed
func parseFlags(args []string, flags []flagInfo) []string {
outer:
for len(args) > 0 {
for _, f := range flags {
if args[0] == "-"+f.name || args[0] == "--"+f.name {
*f.flag = true
args = args[1:]
continue outer
}
}
break
}
return args
}
func main() {
if len(os.Args) < 2 {
log.Fatal(usage)
@@ -35,23 +58,26 @@ func main() {
case "help":
fmt.Println(usage)
case "cli":
testNames := os.Args[2:]
slow := false
sandbox := false
// get the next arg if it's --slow
if len(os.Args) > 2 {
if os.Args[2] == "--slow" || os.Args[2] == "-slow" {
testNames = os.Args[3:]
slow = true
} else if os.Args[2] == "--sandbox" || os.Args[2] == "-sandbox" {
testNames = os.Args[3:]
sandbox = true
}
}
clients.RunCLI(testNames, slow, sandbox)
waitForDebugger := false
raceDetector := false
testNames := parseFlags(os.Args[2:], []flagInfo{
{"slow", &slow},
{"sandbox", &sandbox},
{"debug", &waitForDebugger},
{"race", &raceDetector},
})
clients.RunCLI(testNames, slow, sandbox, waitForDebugger, raceDetector)
case "tui":
clients.RunTUI()
raceDetector := false
remainingArgs := parseFlags(os.Args[2:], []flagInfo{
{"race", &raceDetector},
})
if len(remainingArgs) > 0 {
log.Fatal("tui only supports the -race argument.")
}
clients.RunTUI(raceDetector)
default:
log.Fatal(usage)
}

2
demo/README.md Normal file
View File

@@ -0,0 +1,2 @@
This directory contains stuff for recording lazygit demos.

112
demo/config.yml Normal file
View File

@@ -0,0 +1,112 @@
# Specify a command to be executed
# like `/bin/bash -l`, `ls`, or any other commands
# the default is bash for Linux
# or powershell.exe for Windows
command: echo "YOU NEED TO SPECIFY YOUR OWN COMMAND WITH THE -d ARG"
# Specify the current working directory path
# the default is the current working directory path
cwd: null
# Export additional ENV variables
env:
recording: true
# Explicitly set the number of columns
# or use `auto` to take the current
# number of columns of your shell
cols: 120 # 100
# Explicitly set the number of rows
# or use `auto` to take the current
# number of rows of your shell
rows: 35 # 30
# Amount of times to repeat GIF
# If value is -1, play once
# If value is 0, loop indefinitely
# If value is a positive number, loop n times
repeat: 0
# Quality
# 1 - 100
# Higher quality seems to make no difference, but running it through
# gifsicle ends up with a much better compressed version.
quality: 100
# Delay between frames in ms
# If the value is `auto` use the actual recording delays
frameDelay: auto
# Maximum delay between frames in ms
# Ignored if the `frameDelay` isn't set to `auto`
# Set to `auto` to prevent limiting the max idle time
maxIdleTime: 2000
# The surrounding frame box
# The `type` can be null, window, floating, or solid`
# To hide the title use the value null
# Don't forget to add a backgroundColor style with a null as type
frameBox:
type: floating
title: Lazygit
style:
border: 0px black solid
backgroundColor: "#1d1d1d"
margin: -5px
# Add a watermark image to the rendered gif
# You need to specify an absolute path for
# the image on your machine or a URL, and you can also
# add your own CSS styles
watermark:
imagePath: null
style:
position: absolute
right: 15px
bottom: 15px
width: 100px
opacity: 0.9
# Cursor style can be one of
# `block`, `underline`, or `bar`
cursorStyle: block
# Font family
# You can use any font that is installed on your machine
# in CSS-like syntax
# Download from:
# https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/DejaVuSansMono.zip
# Not using the mono font because it makes icons too small.
fontFamily: "DejaVuSansM Nerd Font"
# The size of the font
fontSize: 8
# The height of lines
lineHeight: 1
# The spacing between letters
letterSpacing: 0
# Theme
theme:
background: "transparent"
foreground: "#dddad6"
cursor: "#c7c7c7"
black: "#7a7a7a"
red: "#fc4384"
green: "#b3e33b"
yellow: "#ffa727"
blue: "#102895"
magenta: "#c930c7"
cyan: "#00c5c7"
white: "#c7c7c7"
brightBlack: "#676767"
brightRed: "#ff7fac"
brightGreen: "#c8ed71"
brightYellow: "#ebdf86"
brightBlue: "#6871ff"
brightMagenta: "#ff76ff"
brightCyan: "#5ffdff"
brightWhite: "#fffefe"

81
demo/record_demo.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/bin/sh
set -e
TYPE=$1
TEST=$2
usage() {
echo "Usage: $0 [gif|mp4] <test path>"
echo "e.g. using full path: $0 gif pkg/integration/tests/demo/nuke_working_tree.go"
exit 1
}
if [ "$#" -ne 2 ]
then
usage
fi
if [ "$TYPE" != "gif" ] && [ "$TYPE" != "mp4" ]
then
usage
exit 1
fi
if [ -z "$TEST" ]
then
usage
fi
WORKTREE_PATH=$(git worktree list | grep assets | awk '{print $1}')
if [ -z "$WORKTREE_PATH" ]
then
echo "Could not find assets worktree. You'll need to create a worktree for the assets branch using the following command:"
echo "git worktree add .worktrees/assets assets"
echo "The assets branch has no shared history with the main branch: it exists to store assets which are too large to store in the main branch."
exit 1
fi
OUTPUT_DIR="$WORKTREE_PATH/demo"
if ! command -v terminalizer &> /dev/null
then
echo "terminalizer could not be found"
echo "Install it with: npm install -g terminalizer"
exit 1
fi
if ! command -v "gifsicle" &> /dev/null
then
echo "gifsicle could not be found"
echo "Install it with: npm install -g gifsicle"
exit 1
fi
# Get last part of the test path and set that as the output name
# example test path: pkg/integration/tests/01_basic_test.go
# For that we want: NAME=01_basic_test
NAME=$(echo "$TEST" | sed -e 's/.*\///' | sed -e 's/\..*//')
# Add the demo to the tests list (if missing) so that it can be run
go generate pkg/integration/tests/tests.go
mkdir -p "$OUTPUT_DIR"
# First we record the demo into a yaml representation
terminalizer -c demo/config.yml record --skip-sharing -d "go run cmd/integration_test/main.go cli --slow $TEST" "$OUTPUT_DIR/$NAME"
# Then we render it into a gif
terminalizer render "$OUTPUT_DIR/$NAME" -o "$OUTPUT_DIR/$NAME.gif"
# Then we convert it to either an mp4 or gif based on the command line argument
if [ "$TYPE" = "mp4" ]
then
COMPRESSED_PATH="$OUTPUT_DIR/$NAME.mp4"
ffmpeg -y -i "$OUTPUT_DIR/$NAME.gif" -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" "$COMPRESSED_PATH"
else
COMPRESSED_PATH="$OUTPUT_DIR/$NAME-compressed.gif"
gifsicle --colors 256 --use-col=web -O3 < "$OUTPUT_DIR/$NAME.gif" > "$COMPRESSED_PATH"
fi
echo "Demo recorded to $COMPRESSED_PATH"

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ You can add custom command keybindings in your config.yml (accessible by pressin
customCommands:
- key: '<c-r>'
context: 'commits'
command: 'hub browse -- "commit/{{.SelectedLocalCommit.Sha}}"'
command: 'hub browse -- "commit/{{.SelectedLocalCommit.Hash}}"'
- key: 'a'
context: 'files'
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:
| _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 |
| 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 |
@@ -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 |
| 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 |
| outputTitle | The title to display in the popup panel if showOutput is true. If left unset, the command will be used as the title. | no |
| after | Actions to take after the command has completed | no |
Here are the options for the `after` key:
@@ -74,6 +75,7 @@ The permitted contexts are:
| -------------- | -------------------------------------------------------------------------------------------------------- |
| status | The 'Status' tab |
| files | The 'Files' tab |
| worktrees | The 'Worktrees' tab |
| localBranches | The 'Local Branches' tab |
| remotes | The 'Remotes' tab |
| remoteBranches | The context you get when pressing enter on a remote in the remotes tab |
@@ -85,6 +87,11 @@ The permitted contexts are:
| stash | The 'Stash' tab |
| 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
### Common fields
@@ -289,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:
```
SelectedLocalCommit
SelectedReflogCommit
SelectedSubCommit
SelectedCommit
SelectedCommitRange
SelectedFile
SelectedPath
SelectedLocalBranch
@@ -300,10 +306,19 @@ SelectedRemote
SelectedTag
SelectedStashEntry
SelectedCommitFile
SelectedWorktree
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

View File

@@ -1,6 +1,6 @@
# Custom Pagers
Lazygit supports custom pagers, [configured](/docs/Config.md) in the config.yml file (which can be opened by pressing `o` in the Status panel).
Lazygit supports custom pagers, [configured](/docs/Config.md) in the config.yml file (which can be opened by pressing `e` in the Status panel).
Support does not extend to Windows users, because we're making use of a package which doesn't have Windows support.
@@ -26,6 +26,8 @@ git:
![](https://i.imgur.com/QJpQkF3.png)
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
```yaml
@@ -62,3 +64,25 @@ git:
```
If you set `useConfig: true`, lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
## Using external diff commands
Some diff tools can't work as a simple pager like the ones above do, because they need access to the entire diff, so just post-processing git's diff is not enough for them. The most notable example is probably [difftastic](https://difftastic.wilfred.me.uk).
These can be used in lazygit by using the `externalDiffCommand` config; in the case of difftastic, that could be
```yaml
git:
paging:
externalDiffCommand: difft --color=always
```
The `colorArg`, `pager`, and `useConfig` options are not used in this case.
You can add whatever extra arguments you prefer for your difftool; for instance
```yaml
git:
paging:
externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off
```

65
docs/Fixup_Commits.md Normal file
View File

@@ -0,0 +1,65 @@
# Fixup Commits
## Background
There's this common scenario that you have a PR in review, the reviewer is
requesting some changes, and you make those changes and would normally simply
squash them into the original commit that they came from. If you do that,
however, there's no way for the reviewer to see what you changed. You could just
make a separate commit with those changes at the end of the branch, but this is
not ideal because it results in a git history that is not very clean.
To help with this, git has a concept of fixup commits: you do make a separate
commit, but the subject of this commit is the string "fixup! " followed by the
original commit subject. This both tells the reviewer what's going on (you are
making a change that you later will squash into the designated commit), and it
provides an easy way to actually perform this squash operation when you are
ready to do that (before merging).
## Creating fixup commits
You could of course create fixup commits manually by typing in the commit
message with the prefix yourself. But lazygit has an easier way to do that:
in the Commits view, select the commit that you want to create a fixup for, and
press shift-F (for "Create fixup commit for this commit"). This automatically
creates a commit with the appropriate subject line.
Don't confuse this with the lowercase "f" command ("Fixup commit"); that one
squashes the selected commit into its parent, this is not what we want here.
## Creating amend commits
There's a special type of fixup commit that uses "amend!" instead of "fixup!" in
the commit message subject; in addition to fixing up the original commit with
changes it allows you to also (or only) change the commit message of the
original commit. The menu that appears when pressing shift-F has options for
both of these; they bring up a commit message panel similar to when you reword a
commit, but then create the "amend!" commit containing the new message. Note
that in that panel you only type the new message as you want it to be
eventually; lazygit then takes care of formatting the "amend!" commit
appropriately for you (with the subject of your new message moving into the body
of the "amend!" commit).
## Squashing fixup commits
When you're ready to merge the branch and want to squash all these fixup commits
that you created, that's very easy to do: select the first commit of your branch
and hit shift-S (for "Squash all 'fixup!' commits above selected commit
(autosquash)"). Boom, done.
## Finding the commit to create a fixup for
When you are making changes to code that you changed earlier in a long branch,
it can be tedious to find the commit to squash it into. Lazygit has a command to
help you with this, too: in the Files view, press ctrl-f to select the right
base commit in the Commits view automatically. From there, you can either press
shift-F to create a fixup commit for it, or shift-A to amend your changes into
the commit if you haven't published your branch yet.
If you have many modifications in your working copy, it is a good idea to stage
related changes that are meant to go into the same fixup commit; if no changes
are staged, ctrl-f works on all unstaged modifications, and then it might show
an error if it finds multiple different base commits. If you are interested in
what the command does to do its magic, and how you can help it work better, you
may want to read the [design document](dev/Find_Base_Commit_For_Fixup_Design.md)
that describes this.

View File

@@ -1,9 +1,11 @@
# Documentation Overview
* [Configuration](./Config.md).
* [Custom Commands](./Custom_Command_Keybindings.md)
* [Custom Pagers](./Custom_Pagers.md)
* [Keybindings](./keybindings)
* [Undo/Redo](./Undoing.md)
* [Searching/Filtering](./Searching.md)
* [Dev docs](./dev)
# Documentation Overview
* [Configuration](./Config.md).
* [Custom Commands](./Custom_Command_Keybindings.md)
* [Custom Pagers](./Custom_Pagers.md)
* [Dev docs](./dev)
* [Keybindings](./keybindings)
* [Undo/Redo](./Undoing.md)
* [Range Select](./Range_Select.md)
* [Searching/Filtering](./Searching.md)
* [Stacked Branches](./Stacked_Branches.md)

14
docs/Range_Select.md Normal file
View File

@@ -0,0 +1,14 @@
# Range Select
Some actions can be performed on a range of contiguous items. For example:
* staging multiple files at once
* squashing multiple commits at once
* copying (for cherry-pick) multiple commits at once
There are two ways to select a range of items:
1. Sticky range select: Press 'v' to toggle range select, then expand the selection using the up/down arrow key. To reset the selection, press 'v' again.
2. Non-sticky range select: Press shift+up or shift+down to expand the selection. To reset the selection, press up/down without shift.
The sticky option will be more familiar to vim users, and the second option will feel more natural to users who aren't used to doing things in a modal way.
In order to perform an action on a range of items, simply press the normal key for that action. If the action only works on individual items, it will raise an error. This is a new feature and the plan is to incrementally support range select for more and more actions. If there is an action you would like to support range select which currently does not, please raise an issue in the repo.

18
docs/Stacked_Branches.md Normal file
View File

@@ -0,0 +1,18 @@
# Working with stacked branches
When working on a large branch it can often be useful to break it down into
smaller pieces, and it can help to create separate branches for each independent
chunk of changes. For example, you could have one branch for preparatory
refactorings, one for backend changes, and one for frontend changes. Those
branches would then all be stacked onto each other.
Git has support for rebasing such a stack as a whole; you can enable it by
setting the git config `rebase.updateRefs` to true. If you then rebase the
topmost branch of the stack, the other ones in the stack will follow. This
includes interactive rebases, so for example amending a commit in the first
branch of the stack will "just work" in the sense that it keeps the other
branches properly stacked onto it.
Lazygit visualizes the individual branch heads in the stack by marking them with a
cyan asterisk (or a cyan branch symbol if you are using [nerd
fonts](Config.md#display-nerd-fonts-icons)).

View File

@@ -1,9 +1,9 @@
# Undo/Redo in lazygit
![Gif](../../assets/undo2.gif)
You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions.
Undo uses the reflog which is specific to commits and branches so we can't undo changes to the working tree or stash.
## Keybindings:
'z' to undo, 'ctrl+z' to redo
![undo](../../assets/demo/undo-compressed.gif)
## How it works

View File

@@ -2,7 +2,7 @@
## 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
2) wait until Lazygit is idle
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.
### 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()`.

100
docs/dev/Codebase_Guide.md Normal file
View File

@@ -0,0 +1,100 @@
# Lazygit Codebase Guide
## Packages
* `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/cheatsheet`: Generates the keybinding cheatsheets in `docs/keybindings`.
* `pkg/commands/git_commands`: All communication to the git binary happens here. So for example there's a `Checkout` method which calls `git checkout`.
* `pkg/commands/oscommands`: Contains code for talking to the OS, and for invoking commands in general
* `pkg/commands/git_config`: Reading of the git config all happens here.
* `pkg/commands/hosting_service`: Contains code that is specific to git hosting services (aka forges).
* `pkg/commands/models`: Contains model structs that represent commits, branches, files, etc.
* `pkg/commands/patch`: Contains code for parsing and working with git patches
* `pkg/common`: Contains the `Common` struct which holds common dependencies like the logger, i18n, and the user config. Most structs in the code will have a field named `c` which holds a common struct (or a derivative of the common struct).
* `pkg/config`: Contains code relating to the Lazygit user config. Specifically `pkg/config/user_config/go` defines the user config struct and its default values. See [below](#using-userconfig) for some important information about using it.
* `pkg/constants`: Contains some constant strings (e.g. links to docs)
* `pkg/env`: Contains code relating to setting/getting environment variables
* `pkg/i18n`: Contains internationalised strings
* `pkg/integration`: Contains end-to-end tests
* `pkg/jsonschema`: Contains generator for user config JSON schema.
* `pkg/logs`: Contains code for instantiating the logger and for tailing the logs via `lazygit --logs`
* `pkg/tasks`: Contains code for running asynchronous tasks: mostly related to efficiently rendering command output to the main window.
* `pkg/theme`: Contains code related to colour themes.
* `pkg/updates`: Contains code related to Lazygit updates (checking for update, download and installing the update)
* `pkg/utils`: Contains lots of low-level helper functions
* `pkg/gui`: Contains code related to the gui. We've still got a God Struct in the form of our Gui struct, but over time code has been moved out into contexts, controllers, and helpers, and we intend to continue moving more code out over time.
* `pkg/gui/context`: Contains code relating to contexts. There is a context for each view e.g. a branches context, a tags context, etc. Contexts manage state related to the view and receive keypresses.
* `pkg/gui/controllers`: Contains code relating to controllers. Controllers define a list of keybindings and their associated handlers. One controller can be assigned to multiple contexts, and one context can contain multiple controllers.
* `pkg/gui/controllers/helpers`: Contains code that is shared between multiple controllers.
* `pkg/gui/filetree`: Contains code relating to the representation of filetrees.
* `pkg/gui/keybindings`: Contains code for mapping between keybindings and their labels
* `pkg/gui/mergeconflicts`: Contains code relating to the handling of merge conflicts
* `pkg/gui/modes`: Contains code relating to the state of different modes e.g. cherry picking mode, rebase mode.
* `pkg/gui/patch_exploring`: Contains code relating to the state of patch-oriented views like the staging view.
* `pkg/gui/popup`: Contains code that lets you easily raise popups
* `pkg/gui/presentation`: Contains presentation code i.e. code concerned with rendering content inside views
* `pkg/gui/services/custom_commands`: Contains code related to user-defined custom commands.
* `pkg/gui/status`: Contains code for invoking loaders and toasts
* `pkg/gui/style`: Contains code for specifying text styles (colour, bold, etc)
* `pkg/gui/types`: Contains various gui-specific types and interfaces. Lots of code lives here to avoid circular dependencies
* `vendor/github.com/jesseduffield/gocui`: Gocui is the underlying library used for handling the gui event loop, handling keypresses, and rendering the UI. It defines the View struct which our own context structs build upon.
## Important files
* `pkg/config/user_config.go`: defines the user config and default values
* `pkg/gui/keybindings.go`: defines keybindings which have not yet been moved into a controller (originally all keybindings were defined here)
* `pkg/gui/controllers.go`: links up controllers with contexts
* `pkg/gui/controllers/helpers/helpers.go`: defines all the different helper structs
* `pkg/commands/git.go`: defines all the different git command structs
* `pkg/gui/gui.go`: defines the top-level gui state and gui initialisation/run code
* `pkg/gui/layout.go`: defines what happens on each render
* `pkg/gui/controllers/helpers/window_arrangement_helper.go`: defines the layout of the UI and the size/position of each window
* `pkg/gui/context/context.go`: defines the different contexts
* `pkg/gui/context/setup.go`: defines initialisation code for all contexts
* `pkg/gui/context.go`: manages the lifecycle of contexts, the context stack, and focus changes.
* `pkg/gui/types/views.go`: defines views
* `pkg/gui/views.go`: defines the ordering of views (front to back) and their initialisation code
* `pkg/gui/gui_common.go`: defines gui-specific methods that all controllers and helpers have access to
* `pkg/i18n/english.go`: defines the set of i18n strings and their English values
* `pkg/gui/controllers/helpers/refresh_helper.go`: manages refreshing of models. The refresh helper is typically invoked at the end of an action to re-load affected models from git (e.g. re-load branches after doing a git pull)
* `pkg/gui/controllers/quit_actions.go`: contains code that runs when you hit 'escape' on a view (assuming the view doesn't define its own escape handler)
* `vendor/github.com/jesseduffield/gocui/gui.go`: defines the gocui gui struct
* `vendor/github.com/jesseduffield/gocui/view.go`: defines the gocui view struct
## Concepts
* **View**: Views are defined in the gocui package, and they maintain an internal buffer of content which is rendered each time the screen is drawn.
* **Context**: A context is tied to a view and contains some additional state and logic specific to that view e.g. the branches context has code relating specifically to branches, and writes the list of branches to the branches view. Views and contexts share some responsibilities for historical reasons.
* **Controller**: A controller defined keybindings with associated handlers. One controller can be assigned to multiple contexts and one context can have multiple controllers. For example the list controller handles keybindings relating to navigating a list, and is assigned to all list contexts (e.g. the branches context).
* **Helper**: A helper defines shared code used by controllers, or used by some other parts of the application. Often a controller will have a method that ends up needing to be used by another controller, so in that case we move the method out into a helper so that both controllers can use it. We need to do this because controllers cannot refer to other controllers' methods.
In terms of dependencies, controllers sit at the highest level, so they can refer to helpers, contexts, and views (although it's preferable for view-specific code to live in contexts). Helpers can refer to contexts and views, and contexts can only refer to views. Views can't refer to contexts, controllers, or helpers.
* **Window**: A window is a section of the screen which will render a view. Windows are named after the default view that appears there, so for example there is a 'stash' window that is so named because by default the stash view appears there. But if you press enter on a stash entry, the stash entry's files will be shown in a different view, but in the same window.
* **Panel**: The term 'panel' is still used in a few places to refer to either a view or a window, and it's a term that is now deprecated in favour of 'view' and 'window'.
* **Tab**: Each tab in a window (e.g. Files, Worktrees, Submodules) actually has a corresponding view which we bring to the front upon changing tabs.
* **Model**: Representation of a git object e.g. commits, branches, files.
* **ViewModel**: Used by a context to maintain state related to the view.
* **Keybinding**: A keybinding associates a _key_ with an _action_. For example if you press the 'down' arrow, the action performed will be your cursor moving down a list by one.
* **Action**: An action is the thing that happens when you press a key. Often an action will invoke a git command, but not always: for example, navigation actions don't involve git.
* **Common structs**: Most structs have a field named `c` which contains a 'common' struct: a struct containing a bag of dependencies that most structs of the same layer require. For example if you want to access a helper from a controller you can do so with `self.c.Helpers.MyHelper`.
## Event loop and threads
The event loop is managed in the `MainLoop` function of `vendor/github.com/jesseduffield/gocui/gui.go`. Any time there is an event like a key press or a window resize, the event will be processed and then the screen will be redrawn. This involves calling the `layout` function defined in `pkg/gui/layout.go`, which lays out the windows and invokes some on-render hooks.
Often, as part of handling a keypress, we'll want to run some code asynchronously so that it doesn't block the UI thread. For this we'll typically run `self.c.OnWorker(myFunc)`. If the worker wants to then do something on the UI thread again it can call `self.c.OnUIThread(myOtherFunc)`.
## 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
Before we had controllers and contexts, all the code lived directly in the gui package under a gui God Struct. This was fairly bloated and so we split things out to have a better separation of concerns. Nonetheless, it's a big effort to migrate all the code so we still have some logic in the gui struct that ought to live somewhere else. Likewise, we have some keybindings defined in `pkg/gui/keybindings.go` that ought to live on a controller (all keybindings used to be defined in that one file).
The new structure has its own problems: we don't have a clear guide on whether code should live in a controller or helper. The current approach is to put code in a controller until it's needed by another controller, and to then extract it out into a helper. We may be better off just putting code in helpers to start with and leaving controllers super-thin, with the responsibility of just pairing keys with corresponding helper functions. But it's not clear to me if that would be better than the current approach.

View File

@@ -0,0 +1,82 @@
# Demo Recordings
We want our demo recordings to be consistent and easy to update if we make changes to Lazygit's UI. Luckily for us, we have an existing recording system for the sake of our integration tests, so we can piggyback on that.
You'll want to familiarise yourself with how integration tests are written: see [here](../../pkg/integration/README.md).
## Prerequisites
Ideally we'd run this whole thing through docker but we haven't got that working. So you will need:
```
# for recording
npm i -g terminalizer
# for gif compression
npm i -g gifsicle
# for mp4 conversion
brew install ffmpeg
# font with icons
wget https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/DejaVuSansMono.tar.xz && \
tar -xf DejaVuSansMono.tar.xz -C /usr/local/share/fonts && \
rm DejaVuSansMono.tar.xz
```
## Creating a demo
Demos are found in `pkg/integration/tests/demo/`. They are like regular integration tests but have `IsDemo: true` which has a few effects:
* The bottom row of the UI is quieter so that we can render captions
* Fetch/Push/Pull have artificial latency to mimic a network request
* The loader at the bottom-right does not appear
In demos, we don't need to be as strict in our assertions as we are in tests. But it's still good to have some basic assertions so that if we automate the process of updating demos we'll know if one of them has broken.
You can use the same flow as we use with integration tests when you're writing a demo:
* Setup the repo
* Run the demo in sandbox mode to get a feel of what needs to happen
* Come back and write the code to make it happen
### Adding captions
It's good to add captions explaining what task if being performed. Use the existing demos as a guide.
### Setting up the assets worktree
We store assets (which includes demo recordings) in the `assets` branch, which is a branch that shares no history with the main branch and exists purely for storing assets. Storing them separately means we don't clog up the code branches with large binaries.
The scripts and demo definitions live in the code branches but the output lives in the assets branch so to be able to create a video from a demo you'll need to create a linked worktree for the assets branch which you can do with:
```sh
git worktree add .worktrees/assets assets
```
Outputs will be stored in `.worktrees/assets/demos/`. We'll store three separate things:
* the yaml of the recording
* the original gif
* either the compressed gif or the mp4 depending on the output you chose (see below)
### Recording the demo
Once you're happy with your demo you can record it using:
```sh
scripts/record_demo.sh [gif|mp4] <path>
# e.g.
scripts/record_demo.sh gif pkg/integration/tests/demo/interactive_rebase.go
```
~~The gif format is for use in the first video of the readme (it has a larger size but has auto-play and looping)~~
~~The mp4 format is for everything else (no looping, requires clicking, but smaller size).~~
Turns out that you can't store mp4s in a repo and link them from a README so we're gonna just use gifs across the board for now.
### Including demos in README/docs
If you've followed the above steps you'll end up with your output in your assets worktree.
Within that worktree, stage all three output files and raise a PR against the assets branch.
Then back in the code branch, in the doc, you can embed the recording like so:
```md
![Nuke working tree](../assets/demo/interactive_rebase-compressed.gif)
```
This means we can update assets without needing to update the docs that embed them.

View 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.

69
docs/dev/Profiling.md Normal file
View File

@@ -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.

View File

@@ -1,4 +1,8 @@
# Dev Documentation Overview
* [Busy/Idle tracking](./Busy.md).
* [Codebase Guide](./Codebase_Guide.md)
* [Busy/Idle Tracking](./Busy.md)
* [Integration Tests](../../pkg/integration/README.md)
* [Demo Recordings](./Demo_Recordings.md)
* [Find base commit for fixup design](Find_Base_Commit_For_Fixup_Design.md)
* [Profiling](Profiling.md)

View File

@@ -1,4 +1,4 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit Keybindings
@@ -6,328 +6,369 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
## Global keybindings
<pre>
<kbd>&lt;c-r&gt;</kbd>: Switch to a recent repo
<kbd>&lt;pgup&gt;</kbd>: Scroll up main panel (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: Scroll down main panel (fn+down/shift+j)
<kbd>@</kbd>: Open command log menu
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
<kbd>:</kbd>: Execute custom command
<kbd>&lt;c-p&gt;</kbd>: View custom patch options
<kbd>m</kbd>: View merge/rebase options
<kbd>R</kbd>: Refresh
<kbd>+</kbd>: Next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: Prev screen mode
<kbd>?</kbd>: Open menu
<kbd>&lt;c-s&gt;</kbd>: View filter-by-path options
<kbd>W</kbd>: Open diff menu
<kbd>&lt;c-e&gt;</kbd>: Open diff menu
<kbd>&lt;c-w&gt;</kbd>: Toggle whether or not whitespace changes are shown in the diff view
<kbd>z</kbd>: Undo
<kbd>&lt;c-z&gt;</kbd>: Redo
<kbd>P</kbd>: Push
<kbd>p</kbd>: Pull
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | Switch to a recent repo | |
| `` <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 `` | 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. |
| `` ) `` | 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 `` | 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`. |
| `` + `` | 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 `` | Quit | |
| `` <esc> `` | Cancel | |
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | Undo | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
| `` <c-z> `` | Redo | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
## List panel navigation
<pre>
<kbd>,</kbd>: Previous page
<kbd>.</kbd>: Next page
<kbd>&lt;</kbd>: Scroll to top
<kbd>&gt;</kbd>: Scroll to bottom
<kbd>/</kbd>: Search the current view by text
<kbd>H</kbd>: Scroll left
<kbd>L</kbd>: Scroll right
<kbd>]</kbd>: Next tab
<kbd>[</kbd>: Previous tab
</pre>
| 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 | |
## Commit files
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy the committed file name to the clipboard
<kbd>c</kbd>: Checkout file
<kbd>d</kbd>: Discard this commit's changes to this file
<kbd>o</kbd>: Open file
<kbd>e</kbd>: Edit file
<kbd>&lt;space&gt;</kbd>: Toggle file included in patch
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
<kbd>`</kbd>: Toggle file tree view
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy path to clipboard | |
| `` 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. |
| `` o `` | Open file | 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. |
| `` - `` | 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 | |
## Commit summary
<pre>
<kbd>&lt;enter&gt;</kbd>: Confirm
<kbd>&lt;esc&gt;</kbd>: Close
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Confirm | |
| `` <esc> `` | Close | |
## Commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>b</kbd>: View bisect options
<kbd>s</kbd>: Squash down
<kbd>f</kbd>: Fixup commit
<kbd>r</kbd>: Reword commit
<kbd>R</kbd>: Reword commit with editor
<kbd>d</kbd>: Delete commit
<kbd>e</kbd>: Edit commit
<kbd>p</kbd>: Pick commit (when mid-rebase)
<kbd>F</kbd>: Create fixup commit for this commit
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
<kbd>&lt;c-j&gt;</kbd>: Move commit down one
<kbd>&lt;c-k&gt;</kbd>: Move commit up one
<kbd>v</kbd>: Paste commits (cherry-pick)
<kbd>A</kbd>: Amend commit with staged changes
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: Revert commit
<kbd>T</kbd>: Tag commit
<kbd>&lt;c-l&gt;</kbd>: Open log menu
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: Copy commit (cherry-pick)
<kbd>C</kbd>: Copy commit range (cherry-pick)
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: Search the current view by text
</pre>
| 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 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 squash, but the selected commit's message will be discarded. |
| `` r `` | Reword | Reword the selected commit's message. |
| `` 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. |
| `` e `` | Edit (start interactive rebase) | Edit the selected commit. Use this to start an interactive rebase from the selected commit. When already mid-rebase, this will mark the selected commit for editing, which means that upon continuing the rebase, the rebase will pause at the selected commit to allow you to make changes. |
| `` 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 `` | 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 | 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> `` | Move commit down one | |
| `` <c-k> `` | Move commit up one | |
| `` V `` | Paste (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 `` | Amend | Amend commit with staged changes. If the selected commit is the HEAD commit, this will perform `git commit --amend`. Otherwise the commit will be amended via a rebase. |
| `` a `` | Amend commit attribute | 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 `` | 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> `` | 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). |
| `` 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 `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
## Confirmation panel
<pre>
<kbd>&lt;enter&gt;</kbd>: Confirm
<kbd>&lt;esc&gt;</kbd>: Close/Cancel
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Confirm | |
| `` <esc> `` | Close/Cancel | |
## Files
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy the file name to the clipboard
<kbd>d</kbd>: View 'discard changes' options
<kbd>&lt;space&gt;</kbd>: Toggle staged
<kbd>&lt;c-b&gt;</kbd>: Filter files by status
<kbd>c</kbd>: Commit changes
<kbd>w</kbd>: Commit changes without pre-commit hook
<kbd>A</kbd>: Amend last commit
<kbd>C</kbd>: Commit changes using git editor
<kbd>e</kbd>: Edit file
<kbd>o</kbd>: Open file
<kbd>i</kbd>: Ignore or exclude file
<kbd>r</kbd>: Refresh files
<kbd>s</kbd>: Stash all changes
<kbd>S</kbd>: View stash options
<kbd>a</kbd>: Stage/unstage all
<kbd>&lt;enter&gt;</kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
<kbd>g</kbd>: View upstream reset options
<kbd>D</kbd>: View reset options
<kbd>`</kbd>: Toggle file tree view
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>f</kbd>: Fetch
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy path to clipboard | |
| `` <space> `` | Stage | Toggle staged for selected file. |
| `` <c-b> `` | Filter files by status | |
| `` y `` | Copy to clipboard | |
| `` c `` | Commit | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` A `` | Amend last commit | |
| `` 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> |
| `` e `` | Edit | Open file in external editor. |
| `` o `` | Open file | Open file in default application. |
| `` i `` | Ignore or exclude file | |
| `` r `` | Refresh files | |
| `` 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 all | Toggle staged/unstaged for all files in working tree. |
| `` <enter> `` | Stage lines / Collapse directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
| `` 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). |
| `` ` `` | 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 `` | 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 | |
## Local branches
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy branch name to clipboard
<kbd>i</kbd>: Show git-flow options
<kbd>&lt;space&gt;</kbd>: Checkout
<kbd>n</kbd>: New branch
<kbd>o</kbd>: Create pull request
<kbd>O</kbd>: Create pull request options
<kbd>&lt;c-y&gt;</kbd>: Copy pull request URL to clipboard
<kbd>c</kbd>: Checkout by name
<kbd>F</kbd>: Force checkout
<kbd>d</kbd>: Delete branch
<kbd>r</kbd>: Rebase checked-out branch onto this branch
<kbd>M</kbd>: Merge into currently checked out branch
<kbd>f</kbd>: Fast-forward this branch from its upstream
<kbd>T</kbd>: Create tag
<kbd>g</kbd>: View reset options
<kbd>R</kbd>: Rename branch
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy branch name to clipboard | |
| `` i `` | Show git-flow options | |
| `` <space> `` | Checkout | Checkout selected item. |
| `` n `` | New branch | |
| `` o `` | Create pull request | |
| `` O `` | View create pull request options | |
| `` <c-y> `` | Copy pull request URL to clipboard | |
| `` c `` | Checkout by name | Checkout by name. In the input box you can enter '-' to switch to the last 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. |
| `` r `` | Rebase | Rebase the checked-out branch onto the selected 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. |
| `` 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> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Main panel (merging)
<pre>
<kbd>e</kbd>: Edit file
<kbd>o</kbd>: Open file
<kbd>&lt;left&gt;</kbd>: Select previous conflict
<kbd>&lt;right&gt;</kbd>: Select next conflict
<kbd>&lt;up&gt;</kbd>: Select previous hunk
<kbd>&lt;down&gt;</kbd>: Select next hunk
<kbd>z</kbd>: Undo
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>&lt;space&gt;</kbd>: Pick hunk
<kbd>b</kbd>: Pick all hunks
<kbd>&lt;esc&gt;</kbd>: Return to files panel
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Pick hunk | |
| `` b `` | Pick all hunks | |
| `` <up> `` | Previous hunk | |
| `` <down> `` | Next hunk | |
| `` <left> `` | Previous conflict | |
| `` <right> `` | Next conflict | |
| `` z `` | Undo | Undo last merge conflict resolution. |
| `` e `` | Edit file | Open file in external editor. |
| `` o `` | Open file | Open file in default application. |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` <esc> `` | Return to files panel | |
## Main panel (normal)
<pre>
<kbd>mouse wheel down</kbd>: Scroll down (fn+up)
<kbd>mouse wheel up</kbd>: Scroll up (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Scroll down | |
| `` mouse wheel up (fn+down) `` | Scroll up | |
## Main panel (patch building)
<pre>
<kbd>&lt;left&gt;</kbd>: Select previous hunk
<kbd>&lt;right&gt;</kbd>: Select next hunk
<kbd>v</kbd>: Toggle drag select
<kbd>V</kbd>: Toggle drag select
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Open file
<kbd>e</kbd>: Edit file
<kbd>&lt;space&gt;</kbd>: Add/Remove line(s) to patch
<kbd>&lt;esc&gt;</kbd>: Exit custom patch builder
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Go to previous hunk | |
| `` <right> `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Select hunk | Toggle hunk selection mode. |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` o `` | Open file | Open file in default application. |
| `` e `` | Edit file | Open file in external editor. |
| `` <space> `` | Toggle lines in patch | |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | Search the current view by text | |
## Main panel (staging)
<pre>
<kbd>&lt;left&gt;</kbd>: Select previous hunk
<kbd>&lt;right&gt;</kbd>: Select next hunk
<kbd>v</kbd>: Toggle drag select
<kbd>V</kbd>: Toggle drag select
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Open file
<kbd>e</kbd>: Edit file
<kbd>&lt;esc&gt;</kbd>: Return to files panel
<kbd>&lt;tab&gt;</kbd>: Switch to other panel (staged/unstaged changes)
<kbd>&lt;space&gt;</kbd>: Toggle line staged / unstaged
<kbd>d</kbd>: Discard change (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: Commit changes
<kbd>w</kbd>: Commit changes without pre-commit hook
<kbd>C</kbd>: Commit changes using git editor
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Go to previous hunk | |
| `` <right> `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Select hunk | Toggle hunk selection mode. |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` <space> `` | Stage | 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 `` | Open file | Open file in default application. |
| `` e `` | Edit file | Open file in external editor. |
| `` <esc> `` | Return to files panel | |
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
| `` c `` | Commit | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` 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 | |
## Menu
<pre>
<kbd>&lt;enter&gt;</kbd>: Execute
<kbd>&lt;esc&gt;</kbd>: Close
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Execute | |
| `` <esc> `` | Close | |
| `` / `` | Filter the current view by text | |
## Reflog
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: Copy commit (cherry-pick)
<kbd>C</kbd>: Copy commit range (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <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). |
| `` 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 `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-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
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy branch name to clipboard
<kbd>&lt;space&gt;</kbd>: Checkout
<kbd>n</kbd>: New branch
<kbd>M</kbd>: Merge into currently checked out branch
<kbd>r</kbd>: Rebase checked-out branch onto this branch
<kbd>d</kbd>: Delete branch
<kbd>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy branch name to clipboard | |
| `` <space> `` | Checkout | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | New 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. |
| `` 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> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Remotes
<pre>
<kbd>f</kbd>: Fetch remote
<kbd>n</kbd>: Add new remote
<kbd>d</kbd>: Remove remote
<kbd>e</kbd>: Edit remote
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 `` | Fetch | Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches. |
| `` / `` | Filter the current view by text | |
## Stash
<pre>
<kbd>&lt;space&gt;</kbd>: Apply
<kbd>g</kbd>: Pop
<kbd>d</kbd>: Drop
<kbd>n</kbd>: New branch
<kbd>r</kbd>: Rename stash
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Apply | Apply the stash entry to your working directory. |
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` n `` | New branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Rename stash | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Status
<pre>
<kbd>o</kbd>: Open config file
<kbd>e</kbd>: Edit config file
<kbd>u</kbd>: Check for update
<kbd>&lt;enter&gt;</kbd>: Switch to a recent repo
<kbd>a</kbd>: Show all branch logs
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | Open config file | Open file in default application. |
| `` e `` | Edit config file | Open file in external editor. |
| `` u `` | Check for update | |
| `` <enter> `` | Switch to a recent repo | |
| `` a `` | Show/cycle all branch logs | |
## Sub-commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: Copy commit (cherry-pick)
<kbd>C</kbd>: Copy commit range (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <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). |
| `` 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 `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
## Submodules
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy submodule name to clipboard
<kbd>&lt;enter&gt;</kbd>: Enter submodule
<kbd>d</kbd>: Remove submodule
<kbd>u</kbd>: Update submodule
<kbd>n</kbd>: Add new submodule
<kbd>e</kbd>: Update submodule URL
<kbd>i</kbd>: Initialize submodule
<kbd>b</kbd>: View bulk submodule options
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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
<pre>
<kbd>&lt;space&gt;</kbd>: Checkout
<kbd>d</kbd>: Delete tag
<kbd>P</kbd>: Push tag
<kbd>n</kbd>: Create tag
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` 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> `` | Open external diff tool (git difftool) | |
| `` <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 | |

View File

@@ -1,4 +1,4 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit キーバインド
@@ -6,328 +6,369 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
## グローバルキーバインド
<pre>
<kbd>&lt;c-r&gt;</kbd>: 最近使用したリポジトリに切り替え
<kbd>&lt;pgup&gt;</kbd>: メインパネルを上にスクロール (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: メインパネルをにスクロール (fn+down/shift+j)
<kbd>@</kbd>: コマンドログメニューを開く
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
<kbd>:</kbd>: カスタムコマンドを実行
<kbd>&lt;c-p&gt;</kbd>: View custom patch options
<kbd>m</kbd>: View merge/rebase options
<kbd>R</kbd>: リフレッシュ
<kbd>+</kbd>: 次のスクリーンモード (normal/half/fullscreen)
<kbd>_</kbd>: 前のスクリーンモード
<kbd>?</kbd>: メニューを開く
<kbd>&lt;c-s&gt;</kbd>: View filter-by-path options
<kbd>W</kbd>: 差分メニューを開く
<kbd>&lt;c-e&gt;</kbd>: 差分メニューを開く
<kbd>&lt;c-w&gt;</kbd>: 空白文字の差分の表示有無を切り替え
<kbd>z</kbd>: アンドゥ (via reflog) (experimental)
<kbd>&lt;c-z&gt;</kbd>: リドゥ (via reflog) (experimental)
<kbd>P</kbd>: Push
<kbd>p</kbd>: Pull
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | 最近使用したリポジトリに切り替え | |
| `` <pgup> (fn+up/shift+k) `` | メインパネルをにスクロール | |
| `` <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 | 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. |
| `` ) `` | 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 `` | 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`. |
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
| `` _ `` | 前のスクリーンモード | |
| `` ? `` | メニューを開く | |
| `` <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. |
| `` <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 `` | 終了 | |
| `` <esc> `` | キャンセル | |
| `` <c-w> `` | 空白文字の差分の表示有無を切り替え | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | アンドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
| `` <c-z> `` | リドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
## 一覧パネルの操作
<pre>
<kbd>,</kbd>: 前のページ
<kbd>.</kbd>: 次のページ
<kbd>&lt;</kbd>: 最上部までスクロール
<kbd>&gt;</kbd>:部までスクロール
<kbd>/</kbd>: 検索を開始
<kbd>H</kbd>: 左スクロール
<kbd>L</kbd>: 右スクロール
<kbd>]</kbd>: 次のタブ
<kbd>[</kbd>: 前のタブ
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | 前のページ | |
| `` . `` | 次のページ | |
| `` < `` |部までスクロール | |
| `` > `` | 最下部までスクロール | |
| `` v `` | 範囲選択を切り替え | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | 検索を開始 | |
| `` H `` | 左スクロール | |
| `` L `` | 右スクロール | |
| `` ] `` | 次のタブ | |
| `` [ `` | 前のタブ | |
## Stash
<pre>
<kbd>&lt;space&gt;</kbd>: 適用
<kbd>g</kbd>: Pop
<kbd>d</kbd>: Drop
<kbd>n</kbd>: 新しいブランチを作成
<kbd>r</kbd>: Stashを変更
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 適用 | Apply the stash entry to your working directory. |
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` 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 `` | Stashを変更 | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Sub-commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: コミットのSHAをクリップボードにコピー
<kbd>&lt;space&gt;</kbd>: コミットをチェックアウト
<kbd>y</kbd>: コミットの情報をコピー
<kbd>o</kbd>: ブラウザでコミットを開く
<kbd>n</kbd>: コミットにブランチを作成
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: コミットをコピー (cherry-pick)
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: 検索を開始
</pre>
| 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 `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | 検索を開始 | |
## Worktrees
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | New worktree | |
| `` <space> `` | Switch | Switch to the selected worktree. |
| `` o `` | Open in editor | |
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |
## コミット
<pre>
<kbd>&lt;c-o&gt;</kbd>: コミットのSHAをクリップボードにコピー
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>b</kbd>: View bisect options
<kbd>s</kbd>: Squash down
<kbd>f</kbd>: Fixup commit
<kbd>r</kbd>: コミットメッセージを変更
<kbd>R</kbd>: エディタでコミットメッセージを編集
<kbd>d</kbd>: コミットを削除
<kbd>e</kbd>: コミットを編集
<kbd>p</kbd>: Pick commit (when mid-rebase)
<kbd>F</kbd>: このコミットに対するfixupコミットを作成
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
<kbd>&lt;c-j&gt;</kbd>: コミットを1つ下に移動
<kbd>&lt;c-k&gt;</kbd>: コミットを1つ上に移動
<kbd>v</kbd>: コミットを貼り付け (cherry-pick)
<kbd>A</kbd>: ステージされた変更でamendコミット
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: コミットをrevert
<kbd>T</kbd>: タグを作成
<kbd>&lt;c-l&gt;</kbd>: ログメニューを開く
<kbd>&lt;space&gt;</kbd>: コミットをチェックアウト
<kbd>y</kbd>: コミットの情報をコピー
<kbd>o</kbd>: ブラウザでコミットを開く
<kbd>n</kbd>: コミットにブランチを作成
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: コミットをコピー (cherry-pick)
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: 検索を開始
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` 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. |
| `` 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 `` | エディタでコミットメッセージを編集 | |
| `` 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) | コミットを編集 |
| `` 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 `` | Pick | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
| `` F `` | Fixupコミットを作成 | このコミットに対するfixupコミットを作成 |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
| `` <c-j> `` | コミットを1つ下に移動 | |
| `` <c-k> `` | コミットを1つ上に移動 | |
| `` V `` | コミットを貼り付け (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 `` | Amend | ステージされた変更でamendコミット |
| `` a `` | Amend commit attribute | 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 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. |
| `` <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 `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | 検索を開始 | |
## コミットファイル
<pre>
<kbd>&lt;c-o&gt;</kbd>: コミットされたファイル名をクリップボードにコピー
<kbd>c</kbd>: Checkout file
<kbd>d</kbd>: Discard this commit's changes to this file
<kbd>o</kbd>: ファイルを開く
<kbd>e</kbd>: ファイルを編集
<kbd>&lt;space&gt;</kbd>: Toggle file included in patch
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
<kbd>`</kbd>: ファイルツリーの表示を切り替え
<kbd>/</kbd>: 検索を開始
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
| `` 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. |
| `` o `` | ファイルを開く | 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 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 |
| `` / `` | 検索を開始 | |
## コミットメッセージ
<pre>
<kbd>&lt;enter&gt;</kbd>: 確認
<kbd>&lt;esc&gt;</kbd>: 閉じる
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 確認 | |
| `` <esc> `` | 閉じる | |
## サブモジュール
<pre>
<kbd>&lt;c-o&gt;</kbd>: サブモジュール名をクリップボードにコピー
<kbd>&lt;enter&gt;</kbd>: サブモジュールを開く
<kbd>d</kbd>: サブモジュールを削除
<kbd>u</kbd>: サブモジュールを更新
<kbd>n</kbd>: サブモジュールを新規追加
<kbd>e</kbd>: サブモジュールのURLを更新
<kbd>i</kbd>: サブモジュールを初期化
<kbd>b</kbd>: View bulk submodule options
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | サブモジュール名をクリップボードにコピー | |
| `` <enter> `` | Enter | サブモジュールを開く |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | サブモジュールを更新 |
| `` n `` | サブモジュールを新規追加 | |
| `` e `` | サブモジュールのURLを更新 | |
| `` i `` | Initialize | サブモジュールを初期化 |
| `` b `` | View bulk submodule options | |
| `` / `` | Filter the current view by text | |
## ステータス
<pre>
<kbd>o</kbd>: 設定ファイルを開く
<kbd>e</kbd>: 設定ファイルを編集
<kbd>u</kbd>: 更新を確認
<kbd>&lt;enter&gt;</kbd>: 最近使用したリポジトリに切り替え
<kbd>a</kbd>: すべてのブランチログを表示
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | 設定ファイルを開く | Open file in default application. |
| `` e `` | 設定ファイルを編集 | Open file in external editor. |
| `` u `` | 更新を確認 | |
| `` <enter> `` | 最近使用したリポジトリに切り替え | |
| `` a `` | すべてのブランチログを表示 | |
## タグ
<pre>
<kbd>&lt;space&gt;</kbd>: チェックアウト
<kbd>d</kbd>: タグを削除
<kbd>P</kbd>: タグをpush
<kbd>n</kbd>: タグを作成
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: コミットを閲覧
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` 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. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## ファイル
<pre>
<kbd>&lt;c-o&gt;</kbd>: ファイル名をクリップボードにコピー
<kbd>d</kbd>: View 'discard changes' options
<kbd>&lt;space&gt;</kbd>: ステージ/アンステージ
<kbd>&lt;c-b&gt;</kbd>: ファイルをフィルタ (ステージ/アンステージ)
<kbd>c</kbd>: 変更をコミット
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
<kbd>A</kbd>: 最新のコミットにamend
<kbd>C</kbd>: gitエディタを使用して変更をコミット
<kbd>e</kbd>: ファイルを編集
<kbd>o</kbd>: ファイルを開く
<kbd>i</kbd>: ファイルをignore
<kbd>r</kbd>: ファイルをリフレッシュ
<kbd>s</kbd>: 変更をstash
<kbd>S</kbd>: View stash options
<kbd>a</kbd>: すべての変更をステージ/アンステージ
<kbd>&lt;enter&gt;</kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
<kbd>g</kbd>: View upstream reset options
<kbd>D</kbd>: View reset options
<kbd>`</kbd>: ファイルツリーの表示を切り替え
<kbd>M</kbd>: Git mergetoolを開く
<kbd>f</kbd>: Fetch
<kbd>/</kbd>: 検索を開始
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
| `` <space> `` | ステージ/アンステージ | Toggle staged for selected file. |
| `` <c-b> `` | ファイルをフィルタ (ステージ/アンステージ) | |
| `` y `` | Copy to clipboard | |
| `` c `` | 変更をコミット | Commit staged changes. |
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
| `` A `` | 最新のコミットにamend | |
| `` 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> |
| `` e `` | Edit | Open file in external editor. |
| `` o `` | ファイルを開く | Open file in default application. |
| `` i `` | ファイルをignore | |
| `` r `` | ファイルをリフレッシュ | |
| `` 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 `` | すべての変更をステージ/アンステージ | Toggle staged/unstaged for all files in working tree. |
| `` <enter> `` | Stage lines / Collapse directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
| `` 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). |
| `` ` `` | ファイルツリーの表示を切り替え | 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 `` | Git mergetoolを開く | Run `git mergetool`. |
| `` 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 |
| `` / `` | 検索を開始 | |
## ブランチ
<pre>
<kbd>&lt;c-o&gt;</kbd>: ブランチ名をクリップボードにコピー
<kbd>i</kbd>: Show git-flow options
<kbd>&lt;space&gt;</kbd>: チェックアウト
<kbd>n</kbd>: 新しいブランチを作成
<kbd>o</kbd>: Pull Requestを作成
<kbd>O</kbd>: Create pull request options
<kbd>&lt;c-y&gt;</kbd>: Pull RequestのURLをクリップボードにコピー
<kbd>c</kbd>: Checkout by name
<kbd>F</kbd>: Force checkout
<kbd>d</kbd>: ブランチを削除
<kbd>r</kbd>: Rebase checked-out branch onto this branch
<kbd>M</kbd>: 現在のブランチにマージ
<kbd>f</kbd>: Fast-forward this branch from its upstream
<kbd>T</kbd>: タグを作成
<kbd>g</kbd>: View reset options
<kbd>R</kbd>: ブランチ名を変更
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: コミットを閲覧
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
| `` i `` | Show git-flow options | |
| `` <space> `` | チェックアウト | Checkout selected item. |
| `` n `` | 新しいブランチを作成 | |
| `` o `` | Pull Requestを作成 | |
| `` O `` | View create pull request options | |
| `` <c-y> `` | Pull RequestのURLをクリップボードにコピー | |
| `` c `` | Checkout by name | Checkout by name. In the input box you can enter '-' to switch to the last 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. |
| `` r `` | Rebase | Rebase the checked-out branch onto the selected 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. |
| `` T `` | タグを作成 | |
| `` s `` | 並び替え | |
| `` g `` | Reset | |
| `` R `` | ブランチ名を変更 | |
| `` 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> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## メインパネル (Merging)
<pre>
<kbd>e</kbd>: ファイルを編集
<kbd>o</kbd>: ファイルを開く
<kbd>&lt;left&gt;</kbd>: 前のコンフリクトを選択
<kbd>&lt;right&gt;</kbd>: 次のコンフリクトを選択
<kbd>&lt;up&gt;</kbd>: 前のhunkを選択
<kbd>&lt;down&gt;</kbd>: 次のhunkを選択
<kbd>z</kbd>: アンドゥ
<kbd>M</kbd>: Git mergetoolを開く
<kbd>&lt;space&gt;</kbd>: Pick hunk
<kbd>b</kbd>: Pick all hunks
<kbd>&lt;esc&gt;</kbd>: ファイル一覧に戻る
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Pick hunk | |
| `` b `` | Pick all hunks | |
| `` <up> `` | 前のhunkを選択 | |
| `` <down> `` | 次のhunkを選択 | |
| `` <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> `` | ファイル一覧に戻る | |
## メインパネル (Normal)
<pre>
<kbd>mouse wheel down</kbd>: 下にスクロール (fn+up)
<kbd>mouse wheel up</kbd>: 上にスクロール (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 下にスクロール | |
| `` mouse wheel up (fn+down) `` | 上にスクロール | |
## メインパネル (Patch Building)
<pre>
<kbd>&lt;left&gt;</kbd>: 前のhunkを選択
<kbd>&lt;right&gt;</kbd>: 次のhunkを選択
<kbd>v</kbd>: 範囲選択を切り替え
<kbd>V</kbd>: 範囲選択を切り替え
<kbd>a</kbd>: Hunk選択を切り替え
<kbd>&lt;c-o&gt;</kbd>: 選択されたテキストをクリップボードにコピー
<kbd>o</kbd>: ファイルを開く
<kbd>e</kbd>: ファイルを編集
<kbd>&lt;space&gt;</kbd>: 行をパッチに追加/削除
<kbd>&lt;esc&gt;</kbd>: Exit custom patch builder
<kbd>/</kbd>: 検索を開始
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 前のhunkを選択 | |
| `` <right> `` | 次のhunkを選択 | |
| `` v `` | 範囲選択を切り替え | |
| `` a `` | Hunk選択を切り替え | Toggle hunk selection mode. |
| `` <c-o> `` | 選択されたテキストをクリップボードにコピー | |
| `` o `` | ファイルを開く | Open file in default application. |
| `` e `` | ファイルを編集 | Open file in external editor. |
| `` <space> `` | 行をパッチに追加/削除 | |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | 検索を開始 | |
## メインパネル (Staging)
<pre>
<kbd>&lt;left&gt;</kbd>: 前のhunkを選択
<kbd>&lt;right&gt;</kbd>: 次のhunkを選択
<kbd>v</kbd>: 範囲選択を切り替え
<kbd>V</kbd>: 範囲選択を切り替え
<kbd>a</kbd>: Hunk選択を切り替え
<kbd>&lt;c-o&gt;</kbd>: 選択されたテキストをクリップボードにコピー
<kbd>o</kbd>: ファイルを開く
<kbd>e</kbd>: ファイルを編集
<kbd>&lt;esc&gt;</kbd>: ファイル一覧に戻る
<kbd>&lt;tab&gt;</kbd>: パネルを切り替え
<kbd>&lt;space&gt;</kbd>: 選択行をステージ/アンステージ
<kbd>d</kbd>: 変更を削除 (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: 変更をコミット
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
<kbd>C</kbd>: gitエディタを使用して変更をコミット
<kbd>/</kbd>: 検索を開始
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 前のhunkを選択 | |
| `` <right> `` | 次のhunkを選択 | |
| `` v `` | 範囲選択を切り替え | |
| `` a `` | Hunk選択を切り替え | 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 hunk | Edit selected hunk in external editor. |
| `` c `` | 変更をコミット | Commit staged changes. |
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
| `` C `` | gitエディタを使用して変更をコミット | |
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 検索を開始 | |
## メニュー
<pre>
<kbd>&lt;enter&gt;</kbd>: 実行
<kbd>&lt;esc&gt;</kbd>: 閉じる
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 実行 | |
| `` <esc> `` | 閉じる | |
| `` / `` | Filter the current view by text | |
## リモート
<pre>
<kbd>f</kbd>: リモートをfetch
<kbd>n</kbd>: リモートを新規追加
<kbd>d</kbd>: リモートを削除
<kbd>e</kbd>: リモートを編集
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | リモートを新規追加 | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | Edit | リモートを編集 |
| `` f `` | Fetch | リモートをfetch |
| `` / `` | Filter the current view by text | |
## リモートブランチ
<pre>
<kbd>&lt;c-o&gt;</kbd>: ブランチ名をクリップボードにコピー
<kbd>&lt;space&gt;</kbd>: チェックアウト
<kbd>n</kbd>: 新しいブランチを作成
<kbd>M</kbd>: 現在のブランチにマージ
<kbd>r</kbd>: Rebase checked-out branch onto this branch
<kbd>d</kbd>: ブランチを削除
<kbd>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: コミットを閲覧
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
| `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | 新しいブランチを作成 | |
| `` 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. |
| `` 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 `` | 並び替え | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## 参照ログ
<pre>
<kbd>&lt;c-o&gt;</kbd>: コミットのSHAをクリップボードにコピー
<kbd>&lt;space&gt;</kbd>: コミットをチェックアウト
<kbd>y</kbd>: コミットの情報をコピー
<kbd>o</kbd>: ブラウザでコミットを開く
<kbd>n</kbd>: コミットにブランチを作成
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: コミットをコピー (cherry-pick)
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: コミットを閲覧
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## 確認パネル
<pre>
<kbd>&lt;enter&gt;</kbd>: 確認
<kbd>&lt;esc&gt;</kbd>: 閉じる/キャンセル
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 確認 | |
| `` <esc> `` | 閉じる/キャンセル | |

View File

@@ -1,4 +1,4 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit 키 바인딩
@@ -6,328 +6,369 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
## 글로벌 키 바인딩
<pre>
<kbd>&lt;c-r&gt;</kbd>: 최근에 사용한 저장소로 전환
<kbd>&lt;pgup&gt;</kbd>: 메인 패널을 위로 스크롤 (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: 메인 패널을 아래로로 스크롤 (fn+down/shift+j)
<kbd>@</kbd>: 명령어 로그 메뉴 열기
<kbd>}</kbd>: Diff 보기의 변경 사항 주위에 표시되는 컨텍스트의 크기를 늘리기
<kbd>{</kbd>: Diff 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기
<kbd>:</kbd>: Execute custom command
<kbd>&lt;c-p&gt;</kbd>: 커스텀 Patch 옵션 보기
<kbd>m</kbd>: View merge/rebase options
<kbd>R</kbd>: 새로고침
<kbd>+</kbd>: 다음 스크린 모드 (normal/half/fullscreen)
<kbd>_</kbd>: 이전 스크린 모드
<kbd>?</kbd>: 매뉴 열기
<kbd>&lt;c-s&gt;</kbd>: View filter-by-path options
<kbd>W</kbd>: Diff 메뉴 열기
<kbd>&lt;c-e&gt;</kbd>: Diff 메뉴 열기
<kbd>&lt;c-w&gt;</kbd>: 공백문자를 Diff 뷰에서 표시 여부 전환
<kbd>z</kbd>: 되돌리기 (reflog) (실험적)
<kbd>&lt;c-z&gt;</kbd>: 다시 실행 (reflog) (실험적)
<kbd>P</kbd>: 푸시
<kbd>p</kbd>: 업데이트
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | 최근에 사용한 저장소로 전환 | |
| `` <pgup> (fn+up/shift+k) `` | 메인 패널을 로 스크롤 | |
| `` <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 `` | 업데이트 | 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 보기의 변경 사항 주위에 표시되는 컨텍스트 크기 줄이기 | 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> `` | 커스텀 Patch 옵션 보기 | |
| `` 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`. |
| `` + `` | 다음 스크린 모드 (normal/half/fullscreen) | |
| `` _ `` | 이전 스크린 모드 | |
| `` ? `` | 매뉴 열기 | |
| `` <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. |
| `` <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 `` | 종료 | |
| `` <esc> `` | 취소 | |
| `` <c-w> `` | 공백문자를 Diff 뷰에서 표시 여부 전환 | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | 되돌리기 (reflog) (실험적) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
| `` <c-z> `` | 다시 실행 (reflog) (실험적) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
## List panel navigation
<pre>
<kbd>,</kbd>: 이전 페이지
<kbd>.</kbd>: 다음 페이지
<kbd>&lt;</kbd>: 맨 위로 스크롤
<kbd>&gt;</kbd>:아래로 스크롤
<kbd>/</kbd>: 검색 시작
<kbd>H</kbd>: 우 스크롤
<kbd>L</kbd>: 좌 스크롤
<kbd>]</kbd>: 이전 탭
<kbd>[</kbd>: 다음 탭
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | 이전 페이지 | |
| `` . `` | 다음 페이지 | |
| `` < `` |로 스크롤 | |
| `` > `` | 맨 아래로 스크롤 | |
| `` v `` | 드래그 선택 전환 | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | 검색 시작 | |
| `` H `` | 우 스크롤 | |
| `` L `` | 좌 스크롤 | |
| `` ] `` | 이전 탭 | |
| `` [ `` | 다음 탭 | |
## Reflog
<pre>
<kbd>&lt;c-o&gt;</kbd>: 커밋 SHA를 클립보드에 복사
<kbd>&lt;space&gt;</kbd>: 커밋을 체크아웃
<kbd>y</kbd>: 커밋 attribute 복사
<kbd>o</kbd>: 브라우저에서 커밋 열기
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: 커밋 보기
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | 브라우저에서 커밋 열기 | |
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Stash
<pre>
<kbd>&lt;space&gt;</kbd>: 적용
<kbd>g</kbd>: Pop
<kbd>d</kbd>: Drop
<kbd>n</kbd>: 새 브랜치 생성
<kbd>r</kbd>: Rename stash
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 적용 | Apply the stash entry to your working directory. |
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` 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 `` | Rename stash | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Sub-commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: 커밋 SHA를 클립보드에 복사
<kbd>&lt;space&gt;</kbd>: 커밋을 체크아웃
<kbd>y</kbd>: 커밋 attribute 복사
<kbd>o</kbd>: 브라우저에서 커밋 열기
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
| `` <space> `` | 체크아웃 | Checkout the selected commit as a detached HEAD. |
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | 브라우저에서 커밋 열기 | |
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | 검색 시작 | |
## Worktrees
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | New worktree | |
| `` <space> `` | Switch | Switch to the selected worktree. |
| `` o `` | Open in editor | |
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |
## 메뉴
<pre>
<kbd>&lt;enter&gt;</kbd>: 실행
<kbd>&lt;esc&gt;</kbd>: 닫기
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 실행 | |
| `` <esc> `` | 닫기 | |
| `` / `` | Filter the current view by text | |
## 메인 패널 (Merging)
<pre>
<kbd>e</kbd>: 파일 편집
<kbd>o</kbd>: 파일 닫기
<kbd>&lt;left&gt;</kbd>: 이전 충돌을 선택
<kbd>&lt;right&gt;</kbd>: 다음 충돌을 선택
<kbd>&lt;up&gt;</kbd>: 이전 hunk를 선택
<kbd>&lt;down&gt;</kbd>: 다음 hunk를 선택
<kbd>z</kbd>: 되돌리기
<kbd>M</kbd>: Git mergetool를 열기
<kbd>&lt;space&gt;</kbd>: Pick hunk
<kbd>b</kbd>: Pick all hunks
<kbd>&lt;esc&gt;</kbd>: 파일 목록으로 돌아가기
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Pick hunk | |
| `` b `` | Pick all hunks | |
| `` <up> `` | 이전 hunk를 선택 | |
| `` <down> `` | 다음 hunk를 선택 | |
| `` <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> `` | 파일 목록으로 돌아가기 | |
## 메인 패널 (Normal)
<pre>
<kbd>mouse wheel down</kbd>: 아래로 스크롤 (fn+up)
<kbd>mouse wheel up</kbd>: 위로 스크롤 (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 아래로 스크롤 | |
| `` mouse wheel up (fn+down) `` | 위로 스크롤 | |
## 메인 패널 (Patch Building)
<pre>
<kbd>&lt;left&gt;</kbd>: 이전 hunk를 선택
<kbd>&lt;right&gt;</kbd>: 다음 hunk를 선택
<kbd>v</kbd>: 드래그 선택 전환
<kbd>V</kbd>: 드래그 선택 전환
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: 선택한 텍스트를 클립보드에 복사
<kbd>o</kbd>: 파일 닫기
<kbd>e</kbd>: 파일 편집
<kbd>&lt;space&gt;</kbd>: Line(s)을 패치에 추가/삭제
<kbd>&lt;esc&gt;</kbd>: Exit custom patch builder
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 이전 hunk를 선택 | |
| `` <right> `` | 다음 hunk를 선택 | |
| `` v `` | 드래그 선택 전환 | |
| `` a `` | Toggle select hunk | Toggle hunk selection mode. |
| `` <c-o> `` | 선택한 텍스트를 클립보드에 복사 | |
| `` o `` | 파일 닫기 | Open file in default application. |
| `` e `` | 파일 편집 | Open file in external editor. |
| `` <space> `` | Line(s)을 패치에 추가/삭제 | |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | 검색 시작 | |
## 메인 패널 (Staging)
<pre>
<kbd>&lt;left&gt;</kbd>: 이전 hunk를 선택
<kbd>&lt;right&gt;</kbd>: 다음 hunk를 선택
<kbd>v</kbd>: 드래그 선택 전환
<kbd>V</kbd>: 드래그 선택 전환
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: 선택한 텍스트를 클립보드에 복사
<kbd>o</kbd>: 파일 닫기
<kbd>e</kbd>: 파일 편집
<kbd>&lt;esc&gt;</kbd>: 파일 목록으로 돌아가기
<kbd>&lt;tab&gt;</kbd>: 패널 전환
<kbd>&lt;space&gt;</kbd>: 선택한 행을 staged / unstaged
<kbd>d</kbd>: 변경을 삭제 (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: 커밋 변경내용
<kbd>w</kbd>: Commit changes without pre-commit hook
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 이전 hunk를 선택 | |
| `` <right> `` | 다음 hunk를 선택 | |
| `` v `` | 드래그 선택 전환 | |
| `` a `` | Toggle select hunk | Toggle hunk selection mode. |
| `` <c-o> `` | 선택한 텍스트를 클립보드에 복사 | |
| `` <space> `` | Staged 전환 | 선택한 행을 staged / unstaged |
| `` 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 hunk | Edit selected hunk in external editor. |
| `` c `` | 커밋 변경내용 | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` C `` | Git 편집기를 사용하여 변경 내용을 커밋합니다. | |
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 검색 시작 | |
## 브랜치
<pre>
<kbd>&lt;c-o&gt;</kbd>: 브랜치명을 클립보드에 복사
<kbd>i</kbd>: Git-flow 옵션 보기
<kbd>&lt;space&gt;</kbd>: 체크아웃
<kbd>n</kbd>: 새 브랜치 생성
<kbd>o</kbd>: 풀 리퀘스트 생성
<kbd>O</kbd>: 풀 리퀘스트 생성 옵션
<kbd>&lt;c-y&gt;</kbd>: 풀 리퀘스트 URL을 클립보드에 복사
<kbd>c</kbd>: 이름으로 체크아웃
<kbd>F</kbd>: 강제 체크아웃
<kbd>d</kbd>: 브랜치 삭제
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
<kbd>M</kbd>: 현재 브랜치에 병합
<kbd>f</kbd>: Fast-forward this branch from its upstream
<kbd>T</kbd>: 태그를 생성
<kbd>g</kbd>: View reset options
<kbd>R</kbd>: 브랜치 이름 변경
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: 커밋 보기
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
| `` i `` | Git-flow 옵션 보기 | |
| `` <space> `` | 체크아웃 | Checkout selected item. |
| `` n `` | 새 브랜치 생성 | |
| `` o `` | 풀 리퀘스트 생성 | |
| `` O `` | 풀 리퀘스트 생성 옵션 | |
| `` <c-y> `` | 풀 리퀘스트 URL을 클립보드에 복사 | |
| `` 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. |
| `` d `` | 삭제 | View delete options for local/remote branch. |
| `` r `` | 체크아웃된 브랜치를 이 브랜치에 리베이스 | Rebase the checked-out branch onto the selected 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. |
| `` T `` | 태그를 생성 | |
| `` s `` | Sort order | |
| `` g `` | View reset options | |
| `` R `` | 브랜치 이름 변경 | |
| `` 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> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## 상태
<pre>
<kbd>o</kbd>: 설정 파일 열기
<kbd>e</kbd>: 설정 파일 수정
<kbd>u</kbd>: 업데이트 확인
<kbd>&lt;enter&gt;</kbd>: 최근에 사용한 저장소로 전환
<kbd>a</kbd>: 모든 브랜치 로그 표시
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | 설정 파일 열기 | Open file in default application. |
| `` e `` | 설정 파일 수정 | Open file in external editor. |
| `` u `` | 업데이트 확인 | |
| `` <enter> `` | 최근에 사용한 저장소로 전환 | |
| `` a `` | 모든 브랜치 로그 표시 | |
## 서브모듈
<pre>
<kbd>&lt;c-o&gt;</kbd>: 서브모듈 이름을 클립보드에 복사
<kbd>&lt;enter&gt;</kbd>: 서브모듈 열기
<kbd>d</kbd>: 서브모듈 삭제
<kbd>u</kbd>: 서브모듈 업데이트
<kbd>n</kbd>: 새로운 서브모듈 추가
<kbd>e</kbd>: 서브모듈의 URL을 수정
<kbd>i</kbd>: 서브모듈 초기화
<kbd>b</kbd>: View bulk submodule options
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 서브모듈 이름을 클립보드에 복사 | |
| `` <enter> `` | Enter | 서브모듈 열기 |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | 서브모듈 업데이트 |
| `` n `` | 새로운 서브모듈 추가 | |
| `` e `` | 서브모듈의 URL을 수정 | |
| `` i `` | Initialize | 서브모듈 초기화 |
| `` b `` | View bulk submodule options | |
| `` / `` | Filter the current view by text | |
## 원격
<pre>
<kbd>f</kbd>: 원격을 업데이트
<kbd>n</kbd>: 새로운 Remote 추가
<kbd>d</kbd>: Remote를 삭제
<kbd>e</kbd>: Remote를 수정
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | 새로운 Remote 추가 | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | Edit | Remote를 수정 |
| `` f `` | Fetch | 원격을 업데이트 |
| `` / `` | Filter the current view by text | |
## 원격 브랜치
<pre>
<kbd>&lt;c-o&gt;</kbd>: 브랜치명을 클립보드에 복사
<kbd>&lt;space&gt;</kbd>: 체크아웃
<kbd>n</kbd>: 새 브랜치 생성
<kbd>M</kbd>: 현재 브랜치에 병합
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
<kbd>d</kbd>: 브랜치 삭제
<kbd>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: 커밋 보기
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 브랜치명을 클립보드에 복사 | |
| `` <space> `` | 체크아웃 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | 새 브랜치 생성 | |
| `` 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. |
| `` 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. |
| `` s `` | Sort order | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## 커밋
<pre>
<kbd>&lt;c-o&gt;</kbd>: 커밋 SHA를 클립보드에 복사
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>b</kbd>: Bisect 옵션 보기
<kbd>s</kbd>: Squash down
<kbd>f</kbd>: Fixup commit
<kbd>r</kbd>: 커밋메시지 변경
<kbd>R</kbd>: 에디터에서 커밋메시지 수정
<kbd>d</kbd>: 커밋 삭제
<kbd>e</kbd>: 커밋을 편집
<kbd>p</kbd>: Pick commit (when mid-rebase)
<kbd>F</kbd>: Create fixup commit for this commit
<kbd>S</kbd>: Squash all 'fixup!' commits above selected commit (autosquash)
<kbd>&lt;c-j&gt;</kbd>: 커밋을 1개 아래로 이동
<kbd>&lt;c-k&gt;</kbd>: 커밋을 1개 위로 이동
<kbd>v</kbd>: 커밋을 붙여넣기 (cherry-pick)
<kbd>A</kbd>: Amend commit with staged changes
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: 커밋 되돌리기
<kbd>T</kbd>: Tag commit
<kbd>&lt;c-l&gt;</kbd>: 로그 메뉴 열기
<kbd>&lt;space&gt;</kbd>: 커밋을 체크아웃
<kbd>y</kbd>: 커밋 attribute 복사
<kbd>o</kbd>: 브라우저에서 커밋 열기
<kbd>n</kbd>: 커밋에서 새 브랜치를 만듭니다.
<kbd>g</kbd>: View reset options
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
<kbd>&lt;enter&gt;</kbd>: View selected item's files
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` b `` | Bisect 옵션 보기 | |
| `` 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 squash, but the selected commit's message will be discarded. |
| `` r `` | 커밋메시지 변경 | Reword the selected commit's message. |
| `` 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. |
| `` e `` | Edit (start interactive rebase) | 커밋을 편집 |
| `` 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 `` | Pick | Pick commit (when mid-rebase) |
| `` F `` | Create fixup commit | Create fixup commit for this commit |
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits above selected commit (autosquash) |
| `` <c-j> `` | 커밋을 1개 아래로 이동 | |
| `` <c-k> `` | 커밋을 1개 위로 이동 | |
| `` V `` | 커밋을 붙여넣기 (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 `` | Amend | Amend commit with staged changes |
| `` a `` | Amend commit attribute | 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 `` | 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 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. |
| `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | 브라우저에서 커밋 열기 | |
| `` n `` | 커밋에서 새 브랜치를 만듭니다. | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | 검색 시작 | |
## 커밋 파일
<pre>
<kbd>&lt;c-o&gt;</kbd>: 커밋한 파일명을 클립보드에 복사
<kbd>c</kbd>: Checkout file
<kbd>d</kbd>: Discard this commit's changes to this file
<kbd>o</kbd>: 파일 닫기
<kbd>e</kbd>: 파일 편집
<kbd>&lt;space&gt;</kbd>: Toggle file included in patch
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
<kbd>`</kbd>: 파일 트리뷰로 전환
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
| `` c `` | 체크아웃 | Checkout file |
| `` d `` | Remove | Discard this commit's changes to this file |
| `` o `` | 파일 닫기 | 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 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. |
| `` ` `` | 파일 트리뷰로 전환 | 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 |
| `` / `` | 검색 시작 | |
## 커밋메시지
<pre>
<kbd>&lt;enter&gt;</kbd>: 확인
<kbd>&lt;esc&gt;</kbd>: 닫기
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 확인 | |
| `` <esc> `` | 닫기 | |
## 태그
<pre>
<kbd>&lt;space&gt;</kbd>: 체크아웃
<kbd>d</kbd>: 태그 삭제
<kbd>P</kbd>: 태그를 push
<kbd>n</kbd>: 태그를 생성
<kbd>g</kbd>: View reset options
<kbd>&lt;enter&gt;</kbd>: 커밋 보기
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` 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. |
| `` g `` | 초기화 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## 파일
<pre>
<kbd>&lt;c-o&gt;</kbd>: 파일명을 클립보드에 복사
<kbd>d</kbd>: View 'discard changes' options
<kbd>&lt;space&gt;</kbd>: Staged 전환
<kbd>&lt;c-b&gt;</kbd>: 파일을 필터하기 (Staged/unstaged)
<kbd>c</kbd>: 커밋 변경내용
<kbd>w</kbd>: Commit changes without pre-commit hook
<kbd>A</kbd>: 마지맛 커밋 수정
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
<kbd>e</kbd>: 파일 편집
<kbd>o</kbd>: 파일 닫기
<kbd>i</kbd>: Ignore file
<kbd>r</kbd>: 파일 새로고침
<kbd>s</kbd>: 변경사항을 Stash
<kbd>S</kbd>: Stash 옵션 보기
<kbd>a</kbd>: 모든 변경을 Staged/unstaged으로 전환
<kbd>&lt;enter&gt;</kbd>: Stage individual hunks/lines for file, or collapse/expand for directory
<kbd>g</kbd>: View upstream reset options
<kbd>D</kbd>: View reset options
<kbd>`</kbd>: 파일 트리뷰로 전환
<kbd>M</kbd>: Git mergetool를 열기
<kbd>f</kbd>: Fetch
<kbd>/</kbd>: 검색 시작
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 파일명을 클립보드에 복사 | |
| `` <space> `` | Staged 전환 | Toggle staged for selected file. |
| `` <c-b> `` | 파일을 필터하기 (Staged/unstaged) | |
| `` y `` | 클립보드에 복사 | |
| `` c `` | 커밋 변경내용 | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` A `` | 마지맛 커밋 수정 | |
| `` 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> |
| `` e `` | Edit | Open file in external editor. |
| `` o `` | 파일 닫기 | Open file in default application. |
| `` i `` | Ignore file | |
| `` r `` | 파일 새로고침 | |
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
| `` S `` | Stash 옵션 보기 | View stash options (e.g. stash all, stash staged, stash unstaged). |
| `` a `` | 모든 변경을 Staged/unstaged으로 전환 | Toggle staged/unstaged for all files in working tree. |
| `` <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. |
| `` g `` | View upstream reset options | |
| `` 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. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Git mergetool를 열기 | Run `git mergetool`. |
| `` 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 |
| `` / `` | 검색 시작 | |
## 확인 패널
<pre>
<kbd>&lt;enter&gt;</kbd>: 확인
<kbd>&lt;esc&gt;</kbd>: 닫기/취소
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 확인 | |
| `` <esc> `` | 닫기/취소 | |

View File

@@ -1,4 +1,4 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit Sneltoetsen
@@ -6,328 +6,369 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
## Globale sneltoetsen
<pre>
<kbd>&lt;c-r&gt;</kbd>: Wissel naar een recente repo
<kbd>&lt;pgup&gt;</kbd>: Scroll naar beneden vanaf hoofdpaneel (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: Scroll naar beneden vanaf hoofdpaneel (fn+down/shift+j)
<kbd>@</kbd>: Open command log menu
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
<kbd>:</kbd>: Voer aangepaste commando uit
<kbd>&lt;c-p&gt;</kbd>: Bekijk aangepaste patch opties
<kbd>m</kbd>: Bekijk merge/rebase opties
<kbd>R</kbd>: Verversen
<kbd>+</kbd>: Volgende scherm modus (normaal/half/groot)
<kbd>_</kbd>: Vorige scherm modus
<kbd>?</kbd>: Open menu
<kbd>&lt;c-s&gt;</kbd>: Bekijk scoping opties
<kbd>W</kbd>: Open diff menu
<kbd>&lt;c-e&gt;</kbd>: Open diff menu
<kbd>&lt;c-w&gt;</kbd>: Toggle whether or not whitespace changes are shown in the diff view
<kbd>z</kbd>: Ongedaan maken (via reflog) (experimenteel)
<kbd>&lt;c-z&gt;</kbd>: Redo (via reflog) (experimenteel)
<kbd>P</kbd>: Push
<kbd>p</kbd>: Pull
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | Wissel naar een recente repo | |
| `` <pgup> (fn+up/shift+k) `` | Scroll naar beneden vanaf hoofdpaneel | |
| `` <pgdown> (fn+down/shift+j) `` | Scroll naar beneden vanaf hoofdpaneel | |
| `` @ `` | 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 `` | 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. |
| `` { `` | 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> `` | Bekijk aangepaste patch opties | |
| `` 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`. |
| `` + `` | Volgende scherm modus (normaal/half/groot) | |
| `` _ `` | Vorige scherm modus | |
| `` ? `` | Open menu | |
| `` <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. |
| `` <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 | |
| `` <esc> `` | Annuleren | |
| `` <c-w> `` | Toggle whitespace | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | Ongedaan maken (via reflog) (experimenteel) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
| `` <c-z> `` | Redo (via reflog) (experimenteel) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
## Lijstpaneel navigatie
<pre>
<kbd>,</kbd>: Vorige pagina
<kbd>.</kbd>: Volgende pagina
<kbd>&lt;</kbd>: Scroll naar boven
<kbd>&gt;</kbd>: Scroll naar beneden
<kbd>/</kbd>: Start met zoeken
<kbd>H</kbd>: Scroll left
<kbd>L</kbd>: Scroll right
<kbd>]</kbd>: Volgende tabblad
<kbd>[</kbd>: Vorige tabblad
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | Vorige pagina | |
| `` . `` | Volgende pagina | |
| `` < `` | Scroll naar boven | |
| `` > `` | Scroll naar beneden | |
| `` v `` | Toggle drag selecteer | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | Start met zoeken | |
| `` H `` | Scroll left | |
| `` L `` | Scroll right | |
| `` ] `` | Volgende tabblad | |
| `` [ `` | Vorige tabblad | |
## Bestanden
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer de bestandsnaam naar het klembord
<kbd>d</kbd>: Bekijk 'veranderingen ongedaan maken' opties
<kbd>&lt;space&gt;</kbd>: Toggle staged
<kbd>&lt;c-b&gt;</kbd>: Filter files by status
<kbd>c</kbd>: Commit veranderingen
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
<kbd>A</kbd>: Wijzig laatste commit
<kbd>C</kbd>: Commit veranderingen met de git editor
<kbd>e</kbd>: Verander bestand
<kbd>o</kbd>: Open bestand
<kbd>i</kbd>: Ignore or exclude file
<kbd>r</kbd>: Refresh bestanden
<kbd>s</kbd>: Stash-bestanden
<kbd>S</kbd>: Bekijk stash opties
<kbd>a</kbd>: Toggle staged alle
<kbd>&lt;enter&gt;</kbd>: Stage individuele hunks/lijnen
<kbd>g</kbd>: Bekijk upstream reset opties
<kbd>D</kbd>: Bekijk reset opties
<kbd>`</kbd>: Toggle bestandsboom weergave
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>f</kbd>: Fetch
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
| `` <space> `` | Toggle staged | Toggle staged for selected file. |
| `` <c-b> `` | Filter files by status | |
| `` y `` | Copy to clipboard | |
| `` c `` | Commit veranderingen | Commit staged changes. |
| `` w `` | Commit veranderingen zonder pre-commit hook | |
| `` A `` | Wijzig laatste commit | |
| `` 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> |
| `` e `` | Edit | Open file in external editor. |
| `` o `` | Open bestand | Open file in default application. |
| `` i `` | Ignore or exclude file | |
| `` r `` | Refresh bestanden | |
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
| `` S `` | Bekijk stash opties | View stash options (e.g. stash all, stash staged, stash unstaged). |
| `` a `` | Toggle staged alle | Toggle staged/unstaged for all files in working tree. |
| `` <enter> `` | Stage individuele hunks/lijnen | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
| `` d `` | Bekijk 'veranderingen ongedaan maken' opties | View options for discarding changes to the selected file. |
| `` g `` | Bekijk upstream reset opties | |
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
| `` ` `` | 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. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` 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 | |
## Bevestigingspaneel
<pre>
<kbd>&lt;enter&gt;</kbd>: Bevestig
<kbd>&lt;esc&gt;</kbd>: Sluiten
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Bevestig | |
| `` <esc> `` | Sluiten | |
## Branches
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer branch name naar klembord
<kbd>i</kbd>: Laat git-flow opties zien
<kbd>&lt;space&gt;</kbd>: Uitchecken
<kbd>n</kbd>: Nieuwe branch
<kbd>o</kbd>: Maak een pull-request
<kbd>O</kbd>: Bekijk opties voor pull-aanvraag
<kbd>&lt;c-y&gt;</kbd>: Kopieer de URL van het pull-verzoek naar het klembord
<kbd>c</kbd>: Uitchecken bij naam
<kbd>F</kbd>: Forceer checkout
<kbd>d</kbd>: Verwijder branch
<kbd>r</kbd>: Rebase branch
<kbd>M</kbd>: Merge in met huidige checked out branch
<kbd>f</kbd>: Fast-forward deze branch vanaf zijn upstream
<kbd>T</kbd>: Creëer tag
<kbd>g</kbd>: Bekijk reset opties
<kbd>R</kbd>: Hernoem branch
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: Bekijk commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer branch name naar klembord | |
| `` i `` | Laat git-flow opties zien | |
| `` <space> `` | Uitchecken | Checkout selected item. |
| `` n `` | Nieuwe branch | |
| `` o `` | Maak een pull-request | |
| `` O `` | Bekijk opties voor pull-aanvraag | |
| `` <c-y> `` | Kopieer de URL van het pull-verzoek naar het klembord | |
| `` c `` | Uitchecken bij naam | Checkout by name. In the input box you can enter '-' to switch to the last 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. |
| `` r `` | Rebase branch | Rebase the checked-out branch onto the selected 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. |
| `` T `` | Creëer tag | |
| `` s `` | Sort order | |
| `` g `` | Bekijk reset opties | |
| `` 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. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Commit bericht
<pre>
<kbd>&lt;enter&gt;</kbd>: Bevestig
<kbd>&lt;esc&gt;</kbd>: Sluiten
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Bevestig | |
| `` <esc> `` | Sluiten | |
## Commit bestanden
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer de vastgelegde bestandsnaam naar het klembord
<kbd>c</kbd>: Bestand uitchecken
<kbd>d</kbd>: Uitsluit deze commit zijn veranderingen aan dit bestand
<kbd>o</kbd>: Open bestand
<kbd>e</kbd>: Verander bestand
<kbd>&lt;space&gt;</kbd>: Toggle bestand inbegrepen in patch
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: Enter bestand om geselecteerde regels toe te voegen aan de patch
<kbd>`</kbd>: Toggle bestandsboom weergave
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer de bestandsnaam naar het klembord | |
| `` c `` | Uitchecken | Bestand uitchecken |
| `` d `` | Remove | Uitsluit deze commit zijn veranderingen aan dit bestand |
| `` o `` | Open bestand | Open file in default application. |
| `` e `` | Edit | Open file in external editor. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <space> `` | Toggle bestand inbegrepen in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
| `` 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. |
| `` ` `` | 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 | |
## Commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer commit SHA naar klembord
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (gekopieerde) commits selectie
<kbd>b</kbd>: View bisect options
<kbd>s</kbd>: Squash beneden
<kbd>f</kbd>: Fixup commit
<kbd>r</kbd>: Hernoem commit
<kbd>R</kbd>: Hernoem commit met editor
<kbd>d</kbd>: Verwijder commit
<kbd>e</kbd>: Wijzig commit
<kbd>p</kbd>: Kies commit (wanneer midden in rebase)
<kbd>F</kbd>: Creëer fixup commit
<kbd>S</kbd>: Squash bovenstaande commits
<kbd>&lt;c-j&gt;</kbd>: Verplaats commit 1 naar beneden
<kbd>&lt;c-k&gt;</kbd>: Verplaats commit 1 naar boven
<kbd>v</kbd>: Plak commits (cherry-pick)
<kbd>A</kbd>: Wijzig commit met staged veranderingen
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: Commit ongedaan maken
<kbd>T</kbd>: Tag commit
<kbd>&lt;c-l&gt;</kbd>: Open log menu
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Creëer nieuwe branch van commit
<kbd>g</kbd>: Bekijk reset opties
<kbd>c</kbd>: Kopieer commit (cherry-pick)
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
<kbd>&lt;enter&gt;</kbd>: Bekijk gecommite bestanden
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` 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. |
| `` 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 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. |
| `` e `` | Edit (start interactive rebase) | Wijzig 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`. |
| `` p `` | Pick | Kies commit (wanneer midden in rebase) |
| `` F `` | Creëer fixup commit | Creëer fixup commit |
| `` S `` | Apply fixup commits | Squash bovenstaande commits |
| `` <c-j> `` | Verplaats commit 1 naar beneden | |
| `` <c-k> `` | Verplaats commit 1 naar boven | |
| `` V `` | Plak commits (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 `` | Amend | Wijzig commit met staged veranderingen |
| `` a `` | Amend commit attribute | 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 `` | 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> `` | 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). |
| `` o `` | Open commit in browser | |
| `` n `` | Creëer nieuwe branch van commit | |
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Start met zoeken | |
## Menu
<pre>
<kbd>&lt;enter&gt;</kbd>: Uitvoeren
<kbd>&lt;esc&gt;</kbd>: Sluiten
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Uitvoeren | |
| `` <esc> `` | Sluiten | |
| `` / `` | Filter the current view by text | |
## Mergen
<pre>
<kbd>e</kbd>: Verander bestand
<kbd>o</kbd>: Open bestand
<kbd>&lt;left&gt;</kbd>: Selecteer voorgaand conflict
<kbd>&lt;right&gt;</kbd>: Selecteer volgende conflict
<kbd>&lt;up&gt;</kbd>: Selecteer bovenste hunk
<kbd>&lt;down&gt;</kbd>: Selecteer onderste hunk
<kbd>z</kbd>: Ongedaan maken
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>&lt;space&gt;</kbd>: Kies stuk
<kbd>b</kbd>: Kies beide stukken
<kbd>&lt;esc&gt;</kbd>: Ga terug naar het bestanden paneel
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Kies stuk | |
| `` b `` | Kies beide stukken | |
| `` <up> `` | Selecteer bovenste hunk | |
| `` <down> `` | Selecteer onderste hunk | |
| `` <left> `` | Selecteer voorgaand conflict | |
| `` <right> `` | Selecteer volgende conflict | |
| `` z `` | Ongedaan maken | Undo last merge conflict resolution. |
| `` e `` | Verander bestand | Open file in external editor. |
| `` o `` | Open bestand | Open file in default application. |
| `` M `` | Open external merge tool | Run `git mergetool`. |
| `` <esc> `` | Ga terug naar het bestanden paneel | |
## Normaal
<pre>
<kbd>mouse wheel down</kbd>: Scroll omlaag (fn+up)
<kbd>mouse wheel up</kbd>: Scroll omhoog (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Scroll omlaag | |
| `` mouse wheel up (fn+down) `` | Scroll omhoog | |
## Patch bouwen
<pre>
<kbd>&lt;left&gt;</kbd>: Selecteer de vorige hunk
<kbd>&lt;right&gt;</kbd>: Selecteer de volgende hunk
<kbd>v</kbd>: Toggle drag selecteer
<kbd>V</kbd>: Toggle drag selecteer
<kbd>a</kbd>: Toggle selecteer hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Open bestand
<kbd>e</kbd>: Verander bestand
<kbd>&lt;space&gt;</kbd>: Voeg toe/verwijder lijn(en) in patch
<kbd>&lt;esc&gt;</kbd>: Sluit lijn-bij-lijn modus
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Selecteer de vorige hunk | |
| `` <right> `` | Selecteer de volgende hunk | |
| `` v `` | Toggle drag selecteer | |
| `` a `` | Toggle selecteer hunk | Toggle hunk selection mode. |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` o `` | Open bestand | Open file in default application. |
| `` e `` | Verander bestand | Open file in external editor. |
| `` <space> `` | Voeg toe/verwijder lijn(en) in patch | |
| `` <esc> `` | Sluit lijn-bij-lijn modus | |
| `` / `` | Start met zoeken | |
## Reflog
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer commit SHA naar klembord
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Creëer nieuwe branch van commit
<kbd>g</kbd>: Bekijk reset opties
<kbd>c</kbd>: Kopieer commit (cherry-pick)
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (gekopieerde) commits selectie
<kbd>&lt;enter&gt;</kbd>: Bekijk commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <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). |
| `` o `` | Open commit in browser | |
| `` n `` | Creëer nieuwe branch van commit | |
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Remote branches
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer branch name naar klembord
<kbd>&lt;space&gt;</kbd>: Uitchecken
<kbd>n</kbd>: Nieuwe branch
<kbd>M</kbd>: Merge in met huidige checked out branch
<kbd>r</kbd>: Rebase branch
<kbd>d</kbd>: Verwijder branch
<kbd>u</kbd>: Stel in als upstream van uitgecheckte branch
<kbd>g</kbd>: Bekijk reset opties
<kbd>&lt;enter&gt;</kbd>: Bekijk commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer branch name naar klembord | |
| `` <space> `` | Uitchecken | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | Nieuwe 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. |
| `` d `` | Delete | Delete the remote branch from the remote. |
| `` u `` | Set as upstream | Stel in als upstream van uitgecheckte branch |
| `` s `` | Sort order | |
| `` 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 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Remotes
<pre>
<kbd>f</kbd>: Fetch remote
<kbd>n</kbd>: Voeg een nieuwe remote toe
<kbd>d</kbd>: Verwijder remote
<kbd>e</kbd>: Wijzig remote
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | Voeg een nieuwe remote toe | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | Edit | Wijzig remote |
| `` f `` | Fetch | Fetch remote |
| `` / `` | Filter the current view by text | |
## Staging
<pre>
<kbd>&lt;left&gt;</kbd>: Selecteer de vorige hunk
<kbd>&lt;right&gt;</kbd>: Selecteer de volgende hunk
<kbd>v</kbd>: Toggle drag selecteer
<kbd>V</kbd>: Toggle drag selecteer
<kbd>a</kbd>: Toggle selecteer hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Open bestand
<kbd>e</kbd>: Verander bestand
<kbd>&lt;esc&gt;</kbd>: Ga terug naar het bestanden paneel
<kbd>&lt;tab&gt;</kbd>: Ga naar een ander paneel
<kbd>&lt;space&gt;</kbd>: Toggle lijnen staged / unstaged
<kbd>d</kbd>: Verwijdert change (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: Commit veranderingen
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
<kbd>C</kbd>: Commit veranderingen met de git editor
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Selecteer de vorige hunk | |
| `` <right> `` | Selecteer de volgende hunk | |
| `` v `` | Toggle drag selecteer | |
| `` a `` | Toggle selecteer hunk | Toggle hunk selection mode. |
| `` <c-o> `` | Copy selected text to clipboard | |
| `` <space> `` | Toggle staged | Toggle lijnen staged / unstaged |
| `` d `` | Verwijdert change (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
| `` o `` | Open bestand | Open file in default application. |
| `` e `` | Verander bestand | Open file in external editor. |
| `` <esc> `` | Ga terug naar het bestanden paneel | |
| `` <tab> `` | Ga naar een ander paneel | Switch to other view (staged/unstaged changes). |
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
| `` c `` | Commit veranderingen | Commit staged changes. |
| `` w `` | Commit veranderingen zonder pre-commit hook | |
| `` 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 | |
## Stash
<pre>
<kbd>&lt;space&gt;</kbd>: Toepassen
<kbd>g</kbd>: Pop
<kbd>d</kbd>: Laten vallen
<kbd>n</kbd>: Nieuwe branch
<kbd>r</kbd>: Rename stash
<kbd>&lt;enter&gt;</kbd>: Bekijk gecommite bestanden
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Toepassen | Apply the stash entry to your working directory. |
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | Laten vallen | Remove the stash entry from the stash list. |
| `` n `` | Nieuwe branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Rename stash | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Status
<pre>
<kbd>o</kbd>: Open config bestand
<kbd>e</kbd>: Verander config bestand
<kbd>u</kbd>: Check voor updates
<kbd>&lt;enter&gt;</kbd>: Wissel naar een recente repo
<kbd>a</kbd>: Alle logs van de branch laten zien
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | Open config bestand | Open file in default application. |
| `` e `` | Verander config bestand | Open file in external editor. |
| `` u `` | Check voor updates | |
| `` <enter> `` | Wissel naar een recente repo | |
| `` a `` | Alle logs van de branch laten zien | |
## Sub-commits
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer commit SHA naar klembord
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Creëer nieuwe branch van commit
<kbd>g</kbd>: Bekijk reset opties
<kbd>c</kbd>: Kopieer commit (cherry-pick)
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (gekopieerde) commits selectie
<kbd>&lt;enter&gt;</kbd>: Bekijk gecommite bestanden
<kbd>/</kbd>: Start met zoeken
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <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). |
| `` o `` | Open commit in browser | |
| `` n `` | Creëer nieuwe branch van commit | |
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Start met zoeken | |
## Submodules
<pre>
<kbd>&lt;c-o&gt;</kbd>: Kopieer submodule naam naar klembord
<kbd>&lt;enter&gt;</kbd>: Enter submodule
<kbd>d</kbd>: Remove submodule
<kbd>u</kbd>: Update submodule
<kbd>n</kbd>: Voeg nieuwe submodule toe
<kbd>e</kbd>: Update submodule URL
<kbd>i</kbd>: Initialiseer submodule
<kbd>b</kbd>: Bekijk bulk submodule opties
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer submodule naam naar klembord | |
| `` <enter> `` | Enter | Enter submodule |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | Update selected submodule. |
| `` n `` | Voeg nieuwe submodule toe | |
| `` e `` | Update submodule URL | |
| `` i `` | Initialize | Initialiseer submodule |
| `` b `` | Bekijk bulk submodule opties | |
| `` / `` | Filter the current view by text | |
## Tags
<pre>
<kbd>&lt;space&gt;</kbd>: Uitchecken
<kbd>d</kbd>: Verwijder tag
<kbd>P</kbd>: Push tag
<kbd>n</kbd>: Creëer tag
<kbd>g</kbd>: Bekijk reset opties
<kbd>&lt;enter&gt;</kbd>: Bekijk commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` 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> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Worktrees
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | New worktree | |
| `` <space> `` | Switch | Switch to the selected worktree. |
| `` o `` | Open in editor | |
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |

View File

@@ -1,333 +1,374 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit Keybindings
# Lazygit Skróty klawiszowe
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
_Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
## Globalne
## Globalne skróty klawiszowe
<pre>
<kbd>&lt;c-r&gt;</kbd>: Switch to a recent repo
<kbd>&lt;pgup&gt;</kbd>: Scroll up main panel (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: Scroll down main panel (fn+down/shift+j)
<kbd>@</kbd>: Open command log menu
<kbd>}</kbd>: Increase the size of the context shown around changes in the diff view
<kbd>{</kbd>: Decrease the size of the context shown around changes in the diff view
<kbd>:</kbd>: Wykonaj własną komendę
<kbd>&lt;c-p&gt;</kbd>: View custom patch options
<kbd>m</kbd>: Widok scalenia/opcje zmiany bazy
<kbd>R</kbd>: Odśwież
<kbd>+</kbd>: Next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: Prev screen mode
<kbd>?</kbd>: Open menu
<kbd>&lt;c-s&gt;</kbd>: View filter-by-path options
<kbd>W</kbd>: Open diff menu
<kbd>&lt;c-e&gt;</kbd>: Open diff menu
<kbd>&lt;c-w&gt;</kbd>: Toggle whether or not whitespace changes are shown in the diff view
<kbd>z</kbd>: Undo
<kbd>&lt;c-z&gt;</kbd>: Redo
<kbd>P</kbd>: Push
<kbd>p</kbd>: Pull
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | Przełącz na ostatnie repozytorium | |
| `` <pgup> (fn+up/shift+k) `` | Przewiń główne okno w górę | |
| `` <pgdown> (fn+down/shift+j) `` | Przewiń główne okno w dół | |
| `` @ `` | Pokaż opcje dziennika poleceń | Pokaż opcje dla dziennika poleceń, np. pokazywanie/ukrywanie dziennika poleceń i skupienie na dzienniku poleceń. |
| `` 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 `` | 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 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. |
| `` } `` | Zwiększ rozmiar kontekstu w widoku różnic | Zwiększ ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
| `` { `` | Zmniejsz rozmiar kontekstu w widoku różnic | Zmniejsz ilość kontekstu pokazywanego wokół zmian w widoku różnic. |
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
| `` <c-p> `` | Wyświetl opcje niestandardowej łatki | |
| `` m `` | Pokaż opcje scalania/rebase | Pokaż opcje do przerwania/kontynuowania/pominięcia bieżącego scalania/rebase. |
| `` 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`. |
| `` + `` | Następny tryb ekranu (normalny/półpełny/pełnoekranowy) | |
| `` _ `` | Poprzedni tryb ekranu | |
| `` ? `` | Otwórz menu przypisań klawiszy | |
| `` <c-s> `` | Pokaż opcje filtrowania | Pokaż opcje filtrowania dziennika commitów, tak aby pokazywane były tylko commity pasujące do filtra. |
| `` 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 | |
| `` <c-w> `` | Przełącz białe znaki | Przełącz czy zmiany białych znaków są pokazywane w widoku różnic. |
| `` z `` | Cofnij | Dziennik reflog zostanie użyty do określenia, jakie polecenie git należy uruchomić, aby cofnąć ostatnie polecenie git. Nie obejmuje to zmian w drzewie roboczym; brane są pod uwagę tylko commity. |
| `` <c-z> `` | Ponów | Dziennik reflog zostanie użyty do określenia, jakie polecenie git należy uruchomić, aby ponowić ostatnie polecenie git. Nie obejmuje to zmian w drzewie roboczym; brane są pod uwagę tylko commity. |
## List panel navigation
## Nawigacja panelu listy
<pre>
<kbd>,</kbd>: Previous page
<kbd>.</kbd>: Next page
<kbd>&lt;</kbd>: Scroll to top
<kbd>&gt;</kbd>: Scroll to bottom
<kbd>/</kbd>: Search the current view by text
<kbd>H</kbd>: Scroll left
<kbd>L</kbd>: Scroll right
<kbd>]</kbd>: Next tab
<kbd>[</kbd>: Previous tab
</pre>
## Commit summary
<pre>
<kbd>&lt;enter&gt;</kbd>: Potwierdź
<kbd>&lt;esc&gt;</kbd>: Zamknij
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | Poprzednia strona | |
| `` . `` | Następna strona | |
| `` < `` | Przewiń do góry | |
| `` > `` | Przewiń do dołu | |
| `` v `` | Przełącz zaznaczenie zakresu | |
| `` <s-down> `` | Zaznacz zakres w dół | |
| `` <s-up> `` | Zaznacz zakres w górę | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
| `` H `` | Przewiń w lewo | |
| `` L `` | Przewiń w prawo | |
| `` ] `` | Następna zakładka | |
| `` [ `` | Poprzednia zakładka | |
## Commity
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>b</kbd>: View bisect options
<kbd>s</kbd>: Ściśnij
<kbd>f</kbd>: Napraw commit
<kbd>r</kbd>: Zmień nazwę commita
<kbd>R</kbd>: Zmień nazwę commita w edytorze
<kbd>d</kbd>: Usuń commit
<kbd>e</kbd>: Edytuj commit
<kbd>p</kbd>: Wybierz commit (podczas zmiany bazy)
<kbd>F</kbd>: Utwórz commit naprawczy dla tego commita
<kbd>S</kbd>: Spłaszcz wszystkie commity naprawcze powyżej zaznaczonych commitów (autosquash)
<kbd>&lt;c-j&gt;</kbd>: Przenieś commit 1 w dół
<kbd>&lt;c-k&gt;</kbd>: Przenieś commit 1 w górę
<kbd>v</kbd>: Wklej commity (przebieranie)
<kbd>A</kbd>: Popraw commit zmianami z poczekalni
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: Odwróć commit
<kbd>T</kbd>: Tag commit
<kbd>&lt;c-l&gt;</kbd>: Open log menu
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>c</kbd>: Kopiuj commit (przebieranie)
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
<kbd>&lt;enter&gt;</kbd>: Przeglądaj pliki commita
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj hash commita do schowka | |
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
| `` b `` | Zobacz opcje bisect | |
| `` s `` | Scal | Scal wybrany commit z commitami poniżej. Wiadomość wybranego commita zostanie dołączona do commita poniżej. |
| `` f `` | Poprawka | Włącz wybrany commit do commita poniżej. Podobnie do fixup, ale wiadomość wybranego commita zostanie odrzucona. |
| `` r `` | Przeformułuj | Przeformułuj wiadomość wybranego commita. |
| `` R `` | Przeformułuj za pomocą edytora | |
| `` 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 `` | 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 `` | 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.
Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, naciśnij `e`. |
| `` p `` | Wybierz | Oznacz wybrany commit do wybrania (podczas rebazowania). Oznacza to, że commit zostanie zachowany po kontynuacji rebazowania. |
| `` 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 `` | Zastosuj commity fixup | Scal wszystkie commity 'fixup!', albo powyżej wybranego commita, albo wszystkie w bieżącej gałęzi (autosquash). |
| `` <c-j> `` | Przesuń commit w dół | |
| `` <c-k> `` | Przesuń commit w górę | |
| `` V `` | Wklej (cherry-pick) | |
| `` 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 `` | 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 `` | Popraw atrybut commita | Ustaw/Resetuj autora commita lub ustaw współautora. |
| `` t `` | Cofnij | Utwórz commit cofający dla wybranego commita, który stosuje zmiany wybranego commita w odwrotnej kolejności. |
| `` T `` | Otaguj commit | Utwórz nowy tag wskazujący na wybrany commit. Zostaniesz poproszony o wprowadzenie nazwy tagu i opcjonalnego opisu. |
| `` <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 | 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-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` <enter> `` | Wyświetl pliki | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Confirmation panel
## Drzewa pracy
<pre>
<kbd>&lt;enter&gt;</kbd>: Potwierdź
<kbd>&lt;esc&gt;</kbd>: Zamknij
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | Nowe drzewo pracy | |
| `` <space> `` | Przełącz | Przełącz do wybranego drzewa pracy. |
| `` o `` | Otwórz w edytorze | |
| `` d `` | Usuń | Usuń wybrane drzewo pracy. To usunie zarówno katalog drzewa pracy, jak i metadane o drzewie pracy w katalogu .git. |
| `` / `` | Filtruj bieżący widok po tekście | |
## Local branches
## Główny panel (budowanie łatki)
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy branch name to clipboard
<kbd>i</kbd>: Show git-flow options
<kbd>&lt;space&gt;</kbd>: Przełącz
<kbd>n</kbd>: Nowa gałąź
<kbd>o</kbd>: Utwórz żądanie pobrania
<kbd>O</kbd>: Utwórz opcje żądania ściągnięcia
<kbd>&lt;c-y&gt;</kbd>: Skopiuj adres URL żądania pobrania do schowka
<kbd>c</kbd>: Przełącz używając nazwy
<kbd>F</kbd>: Wymuś przełączenie
<kbd>d</kbd>: Usuń gałąź
<kbd>r</kbd>: Zmiana bazy gałęzi
<kbd>M</kbd>: Scal do obecnej gałęzi
<kbd>f</kbd>: Fast-forward this branch from its upstream
<kbd>T</kbd>: Create tag
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>R</kbd>: Rename branch
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 | |
| `` 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 | |
## Main panel (patch building)
## Lokalne gałęzie
<pre>
<kbd>&lt;left&gt;</kbd>: Poprzedni kawałek
<kbd>&lt;right&gt;</kbd>: Następny kawałek
<kbd>v</kbd>: Toggle drag select
<kbd>V</kbd>: Toggle drag select
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Otwórz plik
<kbd>e</kbd>: Edytuj plik
<kbd>&lt;space&gt;</kbd>: Add/Remove line(s) to patch
<kbd>&lt;esc&gt;</kbd>: Wyście z trybu "linia po linii"
<kbd>/</kbd>: Search the current view by text
</pre>
| 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łąź | |
| `` o `` | Utwórz żądanie ściągnięcia | |
| `` O `` | Zobacz opcje tworzenia pull requesta | |
| `` <c-y> `` | Kopiuj adres URL żądania ściągnięcia do schowka | |
| `` 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 | Wymuś przełączenie wybranej gałęzi. To spowoduje odrzucenie wszystkich lokalnych zmian w drzewie roboczym przed przełączeniem na wybraną gałąź. |
| `` d `` | Usuń | Wyświetl opcje usuwania lokalnej/odległej gałęzi. |
| `` r `` | Przebazuj | Przebazuj przełączoną gałąź na wybraną gałąź. |
| `` M `` | Scal | Scal wybraną gałąź z aktualnie sprawdzoną gałęzią. |
| `` f `` | Szybkie przewijanie | Szybkie przewijanie wybranej gałęzi z jej źródła. |
| `` T `` | Nowy tag | |
| `` s `` | Kolejność sortowania | |
| `` g `` | Reset | |
| `` R `` | Zmień nazwę gałęzi | |
| `` u `` | Pokaż opcje upstream | Pokaż opcje dotyczące upstream gałęzi, np. ustawianie/usuwanie upstream i resetowanie do upstream. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` <enter> `` | Pokaż commity | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |
## Menu
<pre>
<kbd>&lt;enter&gt;</kbd>: Wykonaj
<kbd>&lt;esc&gt;</kbd>: Zamknij
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Wykonaj | |
| `` <esc> `` | Zamknij | |
| `` / `` | Filtruj bieżący widok po tekście | |
## Panel główny (normalny)
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Przewiń w dół | |
| `` mouse wheel up (fn+down) `` | Przewiń w górę | |
## Panel główny (scalanie)
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Wybierz fragment | |
| `` b `` | Wybierz wszystkie fragmenty | |
| `` <up> `` | Poprzedni fragment | |
| `` <down> `` | Następny fragment | |
| `` <left> `` | Poprzedni konflikt | |
| `` <right> `` | Następny konflikt | |
| `` z `` | Cofnij | Cofnij ostatnie rozwiązanie konfliktu scalania. |
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
| `` M `` | Otwórz zewnętrzne narzędzie scalania | Uruchom `git mergetool`. |
| `` <esc> `` | Wróć do panelu plików | |
## Panel główny (zatwierdzanie)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Idź do poprzedniego fragmentu | |
| `` <right> `` | Idź do następnego fragmentu | |
| `` v `` | Przełącz zaznaczenie zakresu | |
| `` a `` | Zaznacz fragment | Przełącz tryb zaznaczania fragmentu. |
| `` <c-o> `` | Kopiuj zaznaczony tekst do schowka | |
| `` <space> `` | Zatwierdź | Przełącz zaznaczenie zatwierdzone/niezatwierdzone. |
| `` d `` | Odrzuć | Gdy zaznaczona jest niezatwierdzona zmiana, odrzuć ją używając `git reset`. Gdy zaznaczona jest zatwierdzona zmiana, cofnij zatwierdzenie. |
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
| `` <esc> `` | Wróć do panelu plików | |
| `` <tab> `` | Przełącz widok | Przełącz na inny widok (zatwierdzone/niezatwierdzone zmiany). |
| `` E `` | Edytuj fragment | Edytuj wybrany fragment w zewnętrznym edytorze. |
| `` c `` | Commit | Zatwierdź zmiany zatwierdzone. |
| `` w `` | Zatwierdź zmiany bez hooka pre-commit | |
| `` C `` | Zatwierdź zmiany używając edytora git | |
| `` <c-f> `` | Znajdź bazowy commit do poprawki | Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Panel potwierdzenia
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Potwierdź | |
| `` <esc> `` | Zamknij/Anuluj | |
## Pliki
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy the file name to the clipboard
<kbd>d</kbd>: Pokaż opcje porzucania zmian
<kbd>&lt;space&gt;</kbd>: Przełącz stan poczekalni
<kbd>&lt;c-b&gt;</kbd>: Filter files by status
<kbd>c</kbd>: Zatwierdź zmiany
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
<kbd>A</kbd>: Zmień ostatni commit
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
<kbd>e</kbd>: Edytuj plik
<kbd>o</kbd>: Otwórz plik
<kbd>i</kbd>: Ignore or exclude file
<kbd>r</kbd>: Odśwież pliki
<kbd>s</kbd>: Przechowaj zmiany
<kbd>S</kbd>: Wyświetl opcje schowka
<kbd>a</kbd>: Przełącz stan poczekalni wszystkich
<kbd>&lt;enter&gt;</kbd>: Zatwierdź pojedyncze linie
<kbd>g</kbd>: View upstream reset options
<kbd>D</kbd>: Wyświetl opcje resetu
<kbd>`</kbd>: Toggle file tree view
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>f</kbd>: Pobierz
<kbd>/</kbd>: Search the current view by text
</pre>
| 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
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy the committed file name to the clipboard
<kbd>c</kbd>: Plik wybierania
<kbd>d</kbd>: Porzuć zmiany commita dla tego pliku
<kbd>o</kbd>: Otwórz plik
<kbd>e</kbd>: Edytuj plik
<kbd>&lt;space&gt;</kbd>: Toggle file included in patch
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
<kbd>`</kbd>: Toggle file tree view
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj ścieżkę 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 | |
## Poczekalnia
## Podsumowanie commita
<pre>
<kbd>&lt;left&gt;</kbd>: Poprzedni kawałek
<kbd>&lt;right&gt;</kbd>: Następny kawałek
<kbd>v</kbd>: Toggle drag select
<kbd>V</kbd>: Toggle drag select
<kbd>a</kbd>: Toggle select hunk
<kbd>&lt;c-o&gt;</kbd>: Copy the selected text to the clipboard
<kbd>o</kbd>: Otwórz plik
<kbd>e</kbd>: Edytuj plik
<kbd>&lt;esc&gt;</kbd>: Wróć do panelu plików
<kbd>&lt;tab&gt;</kbd>: Switch to other panel (staged/unstaged changes)
<kbd>&lt;space&gt;</kbd>: Toggle line staged / unstaged
<kbd>d</kbd>: Discard change (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: Zatwierdź zmiany
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
<kbd>/</kbd>: Search the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Potwierdź | |
| `` <esc> `` | Zamknij | |
## Reflog
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>c</kbd>: Kopiuj commit (przebieranie)
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
## Remote branches
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy branch name to clipboard
<kbd>&lt;space&gt;</kbd>: Przełącz
<kbd>n</kbd>: Nowa gałąź
<kbd>M</kbd>: Scal do obecnej gałęzi
<kbd>r</kbd>: Zmiana bazy gałęzi
<kbd>d</kbd>: Usuń gałąź
<kbd>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
## Remotes
<pre>
<kbd>f</kbd>: Fetch remote
<kbd>n</kbd>: Add new remote
<kbd>d</kbd>: Remove remote
<kbd>e</kbd>: Edit remote
<kbd>/</kbd>: Filter the current view by text
</pre>
## Scalanie
<pre>
<kbd>e</kbd>: Edytuj plik
<kbd>o</kbd>: Otwórz plik
<kbd>&lt;left&gt;</kbd>: Poprzedni konflikt
<kbd>&lt;right&gt;</kbd>: Następny konflikt
<kbd>&lt;up&gt;</kbd>: Wybierz poprzedni kawałek
<kbd>&lt;down&gt;</kbd>: Wybierz następny kawałek
<kbd>z</kbd>: Cofnij
<kbd>M</kbd>: Open external merge tool (git mergetool)
<kbd>&lt;space&gt;</kbd>: Wybierz kawałek
<kbd>b</kbd>: Wybierz oba kawałki
<kbd>&lt;esc&gt;</kbd>: Wróć do panelu plików
</pre>
| 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
<pre>
<kbd>&lt;space&gt;</kbd>: Zastosuj
<kbd>g</kbd>: Wyciągnij
<kbd>d</kbd>: Porzuć
<kbd>n</kbd>: Nowa gałąź
<kbd>r</kbd>: Rename stash
<kbd>&lt;enter&gt;</kbd>: Przeglądaj pliki commita
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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
<pre>
<kbd>o</kbd>: Otwórz konfigurację
<kbd>e</kbd>: Edytuj konfigurację
<kbd>u</kbd>: Sprawdź aktualizacje
<kbd>&lt;enter&gt;</kbd>: Switch to a recent repo
<kbd>a</kbd>: Pokaż wszystkie logi gałęzi
</pre>
| 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-commits
## Sub-commity
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy commit SHA to clipboard
<kbd>&lt;space&gt;</kbd>: Checkout commit
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: Open commit in browser
<kbd>n</kbd>: Create new branch off of commit
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>c</kbd>: Kopiuj commit (przebieranie)
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
<kbd>&lt;c-r&gt;</kbd>: Reset cherry-picked (copied) commits selection
<kbd>&lt;enter&gt;</kbd>: Przeglądaj pliki commita
<kbd>/</kbd>: Search the current view by text
</pre>
| 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 | |
## Submodules
## Submoduły
<pre>
<kbd>&lt;c-o&gt;</kbd>: Copy submodule name to clipboard
<kbd>&lt;enter&gt;</kbd>: Enter submodule
<kbd>d</kbd>: Remove submodule
<kbd>u</kbd>: Update submodule
<kbd>n</kbd>: Add new submodule
<kbd>e</kbd>: Update submodule URL
<kbd>i</kbd>: Initialize submodule
<kbd>b</kbd>: View bulk submodule options
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 | |
## Tags
## Tagi
<pre>
<kbd>&lt;space&gt;</kbd>: Przełącz
<kbd>d</kbd>: Delete tag
<kbd>P</kbd>: Push tag
<kbd>n</kbd>: Create tag
<kbd>g</kbd>: Wyświetl opcje resetu
<kbd>&lt;enter&gt;</kbd>: View commits
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 | |
## Zwykłe
## Zdalne
<pre>
<kbd>mouse wheel down</kbd>: Przewiń w dół (fn+up)
<kbd>mouse wheel up</kbd>: Przewiń w górę (fn+down)
</pre>
| 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 | |

View File

@@ -0,0 +1,378 @@
_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 | |
| `` 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 | |

View File

@@ -1,4 +1,4 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit Связки клавиш
@@ -6,328 +6,369 @@ _Связки клавиш_
## Глобальные сочетания клавиш
<pre>
<kbd>&lt;c-r&gt;</kbd>: Переключиться на последний репозиторий
<kbd>&lt;pgup&gt;</kbd>: Прокрутить вверх главную панель (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: Прокрутить вниз главную панель (fn+down/shift+j)
<kbd>@</kbd>: Открыть меню журнала команд
<kbd>}</kbd>: Увеличить размер контекста, отображаемого вокруг изменений в просмотрщике сравнении
<kbd>{</kbd>: Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении
<kbd>:</kbd>: Выполнить пользовательскую команду
<kbd>&lt;c-p&gt;</kbd>: Просмотреть пользовательские параметры патча
<kbd>m</kbd>: Просмотреть параметры слияния/перебазирования
<kbd>R</kbd>: Обновить
<kbd>+</kbd>: Следующий режим экрана (нормальный/полуэкранный/полноэкранный)
<kbd>_</kbd>: Предыдущий режим экрана
<kbd>?</kbd>: Открыть меню
<kbd>&lt;c-s&gt;</kbd>: Просмотреть параметры фильтрации по пути
<kbd>W</kbd>: Открыть меню сравнении
<kbd>&lt;c-e&gt;</kbd>: Открыть меню сравнении
<kbd>&lt;c-w&gt;</kbd>: Переключить отображение изменении пробелов в просмотрщике сравнении
<kbd>z</kbd>: Отменить (через reflog) (экспериментальный)
<kbd>&lt;c-z&gt;</kbd>: Повторить (через reflog) (экспериментальный)
<kbd>P</kbd>: Отправить изменения
<kbd>p</kbd>: Получить и слить изменения
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | Переключиться на последний репозиторий | |
| `` <pgup> (fn+up/shift+k) `` | Прокрутить вверх главную панель | |
| `` <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 `` | Получить и слить изменения | 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. |
| `` { `` | Уменьшите размер контекста, отображаемого вокруг изменений в просмотрщике сравнении | 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> `` | Просмотреть пользовательские параметры патча | |
| `` 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`. |
| `` + `` | Следующий режим экрана (нормальный/полуэкранный/полноэкранный) | |
| `` _ `` | Предыдущий режим экрана | |
| `` ? `` | Открыть меню | |
| `` <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. |
| `` <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 `` | Выйти | |
| `` <esc> `` | Отменить | |
| `` <c-w> `` | Переключить отображение изменении пробелов в просмотрщике сравнении | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | Отменить (через reflog) (экспериментальный) | Журнал ссылок (reflog) будет использоваться для определения того, какую команду git запустить, чтобы отменить последнюю команду git. Сюда не входят изменения в рабочем дереве; учитываются только коммиты. |
| `` <c-z> `` | Повторить (через reflog) (экспериментальный) | Журнал ссылок (reflog) будет использоваться для определения того, какую команду git нужно запустить, чтобы повторить последнюю команду git. Сюда не входят изменения в рабочем дереве; учитываются только коммиты. |
## Навигация по панели списка
<pre>
<kbd>,</kbd>: Предыдущая страница
<kbd>.</kbd>: Следующая страница
<kbd>&lt;</kbd>: Пролистать наверх
<kbd>&gt;</kbd>: Прокрутить вниз
<kbd>/</kbd>: Найти
<kbd>H</kbd>: Прокрутить влево
<kbd>L</kbd>: Прокрутить вправо
<kbd>]</kbd>: Следующая вкладка
<kbd>[</kbd>: Предыдущая вкладка
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | Предыдущая страница | |
| `` . `` | Следующая страница | |
| `` < `` | Пролистать наверх | |
| `` > `` | Прокрутить вниз | |
| `` v `` | Переключить выборку перетаскивания | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | Найти | |
| `` H `` | Прокрутить влево | |
| `` L `` | Прокрутить вправо | |
| `` ] `` | Следующая вкладка | |
| `` [ `` | Предыдущая вкладка | |
## Worktrees
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | New worktree | |
| `` <space> `` | Switch | Switch to the selected worktree. |
| `` o `` | Open in editor | |
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |
## Главная панель (Индексирование)
<pre>
<kbd>&lt;left&gt;</kbd>: Выбрать предыдущую часть
<kbd>&lt;right&gt;</kbd>: Выбрать следующую часть
<kbd>v</kbd>: Переключить выборку перетаскивания
<kbd>V</kbd>: Переключить выборку перетаскивания
<kbd>a</kbd>: Переключить выборку частей
<kbd>&lt;c-o&gt;</kbd>: Скопировать выделенный текст в буфер обмена
<kbd>o</kbd>: Открыть файл
<kbd>e</kbd>: Редактировать файл
<kbd>&lt;esc&gt;</kbd>: Вернуться к панели файлов
<kbd>&lt;tab&gt;</kbd>: Переключиться на другую панель (проиндексированные/непроиндексированные изменения)
<kbd>&lt;space&gt;</kbd>: Переключить строку в проиндексированные / непроиндексированные
<kbd>d</kbd>: Отменить изменение (git reset)
<kbd>E</kbd>: Изменить эту часть
<kbd>c</kbd>: Сохранить изменения
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
<kbd>/</kbd>: Найти
</pre>
| 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 `` | Закоммитить изменения без предварительного хука коммита | |
| `` C `` | Сохранить изменения с помощью редактора git | |
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Найти | |
## Главная панель (Обычный)
<pre>
<kbd>mouse wheel down</kbd>: Прокрутить вниз (fn+up)
<kbd>mouse wheel up</kbd>: Прокрутить вверх (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Прокрутить вниз | |
| `` mouse wheel up (fn+down) `` | Прокрутить вверх | |
## Главная панель (Слияние)
<pre>
<kbd>e</kbd>: Редактировать файл
<kbd>o</kbd>: Открыть файл
<kbd>&lt;left&gt;</kbd>: Выбрать предыдущий конфликт
<kbd>&lt;right&gt;</kbd>: Выбрать следующий конфликт
<kbd>&lt;up&gt;</kbd>: Выбрать предыдущую часть
<kbd>&lt;down&gt;</kbd>: Выбрать следующую часть
<kbd>z</kbd>: Отменить
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
<kbd>&lt;space&gt;</kbd>: Выбрать эту часть
<kbd>b</kbd>: Выбрать все части
<kbd>&lt;esc&gt;</kbd>: Вернуться к панели файлов
</pre>
| 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> `` | Вернуться к панели файлов | |
## Главная панель (сборка патчей)
<pre>
<kbd>&lt;left&gt;</kbd>: Выбрать предыдущую часть
<kbd>&lt;right&gt;</kbd>: Выбрать следующую часть
<kbd>v</kbd>: Переключить выборку перетаскивания
<kbd>V</kbd>: Переключить выборку перетаскивания
<kbd>a</kbd>: Переключить выборку частей
<kbd>&lt;c-o&gt;</kbd>: Скопировать выделенный текст в буфер обмена
<kbd>o</kbd>: Открыть файл
<kbd>e</kbd>: Редактировать файл
<kbd>&lt;space&gt;</kbd>: Добавить/удалить строку(и) для патча
<kbd>&lt;esc&gt;</kbd>: Выйти из сборщика пользовательских патчей
<kbd>/</kbd>: Найти
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | Выбрать предыдущую часть | |
| `` <right> `` | Выбрать следующую часть | |
| `` v `` | Переключить выборку перетаскивания | |
| `` a `` | Переключить выборку частей | Toggle hunk selection mode. |
| `` <c-o> `` | Скопировать выделенный текст в буфер обмена | |
| `` o `` | Открыть файл | Open file in default application. |
| `` e `` | Редактировать файл | Open file in external editor. |
| `` <space> `` | Добавить/удалить строку(и) для патча | |
| `` <esc> `` | Выйти из сборщика пользовательских патчей | |
| `` / `` | Найти | |
## Журнал ссылок (Reflog)
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать SHA коммита в буфер обмена
<kbd>&lt;space&gt;</kbd>: Переключить коммит
<kbd>y</kbd>: Скопировать атрибут коммита
<kbd>o</kbd>: Открыть коммит в браузере
<kbd>n</kbd>: Создать новую ветку с этого коммита
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
<kbd>&lt;enter&gt;</kbd>: Просмотреть коммиты
<kbd>/</kbd>: Filter the current view by text
</pre>
| 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 `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Коммиты
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать SHA коммита в буфер обмена
<kbd>&lt;c-r&gt;</kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
<kbd>b</kbd>: Просмотреть параметры бинарного поиска
<kbd>s</kbd>: Объединить несколько коммитов в один нижний
<kbd>f</kbd>: Объединить несколько коммитов в один отбросив сообщение коммита
<kbd>r</kbd>: Перефразировать коммит
<kbd>R</kbd>: Переписать коммит с помощью редактора
<kbd>d</kbd>: Удалить коммит
<kbd>e</kbd>: Изменить коммит
<kbd>p</kbd>: Выбрать коммит (в середине перебазирования)
<kbd>F</kbd>: Создать fixup коммит для этого коммита
<kbd>S</kbd>: Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение)
<kbd>&lt;c-j&gt;</kbd>: Переместить коммит вниз на один
<kbd>&lt;c-k&gt;</kbd>: Переместить коммит вверх на один
<kbd>v</kbd>: Вставить отобранные коммиты (cherry-pick)
<kbd>A</kbd>: Править последний коммит с проиндексированными изменениями
<kbd>a</kbd>: Установить/убрать автора коммита
<kbd>t</kbd>: Отменить коммит
<kbd>T</kbd>: Пометить коммит тегом
<kbd>&lt;c-l&gt;</kbd>: Открыть меню журнала
<kbd>&lt;space&gt;</kbd>: Переключить коммит
<kbd>y</kbd>: Скопировать атрибут коммита
<kbd>o</kbd>: Открыть коммит в браузере
<kbd>n</kbd>: Создать новую ветку с этого коммита
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
<kbd>&lt;enter&gt;</kbd>: Просмотреть файлы выбранного элемента
<kbd>/</kbd>: Найти
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать hash коммита в буфер обмена | |
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
| `` 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. |
| `` 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 `` | Переписать коммит с помощью редактора | |
| `` 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) | Изменить коммит |
| `` 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 `` | Pick | Выбрать коммит (в середине перебазирования) |
| `` F `` | Создать fixup коммит | Создать fixup коммит для этого коммита |
| `` S `` | Apply fixup commits | Объединить все 'fixup!' коммиты выше в выбранный коммит (автосохранение) |
| `` <c-j> `` | Переместить коммит вниз на один | |
| `` <c-k> `` | Переместить коммит вверх на один | |
| `` V `` | Вставить отобранные коммиты (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 `` | Amend | Править последний коммит с проиндексированными изменениями |
| `` 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 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. |
| `` <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 `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Найти | |
## Локальные Ветки
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать название ветки в буфер обмена
<kbd>i</kbd>: Показать параметры git-flow
<kbd>&lt;space&gt;</kbd>: Переключить
<kbd>n</kbd>: Новая ветка
<kbd>o</kbd>: Создать запрос на принятие изменений
<kbd>O</kbd>: Создать параметры запроса принятие изменений
<kbd>&lt;c-y&gt;</kbd>: Скопировать URL запроса на принятие изменений в буфер обмена
<kbd>c</kbd>: Переключить по названию
<kbd>F</kbd>: Принудительное переключение
<kbd>d</kbd>: Удалить ветку
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
<kbd>M</kbd>: Слияние с текущей переключённой веткой
<kbd>f</kbd>: Перемотать эту ветку вперёд из её upstream-ветки
<kbd>T</kbd>: Создать тег
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>R</kbd>: Переименовать ветку
<kbd>u</kbd>: Установить/убрать upstream-ветку
<kbd>&lt;enter&gt;</kbd>: Просмотреть коммиты
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
| `` i `` | Показать параметры git-flow | |
| `` <space> `` | Переключить | Checkout selected item. |
| `` n `` | Новая ветка | |
| `` o `` | Создать запрос на принятие изменений | |
| `` O `` | Создать параметры запроса принятие изменений | |
| `` <c-y> `` | Скопировать URL запроса на принятие изменений в буфер обмена | |
| `` 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. |
| `` d `` | Delete | View delete options for local/remote branch. |
| `` r `` | Перебазировать переключённую ветку на эту ветку | Rebase the checked-out branch onto the selected 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. |
| `` T `` | Создать тег | |
| `` s `` | Порядок сортировки | |
| `` g `` | Просмотреть параметры сброса | |
| `` R `` | Переименовать ветку | |
| `` 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> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Меню
<pre>
<kbd>&lt;enter&gt;</kbd>: Выполнить
<kbd>&lt;esc&gt;</kbd>: Закрыть
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Выполнить | |
| `` <esc> `` | Закрыть | |
| `` / `` | Filter the current view by text | |
## Панель Подтверждения
<pre>
<kbd>&lt;enter&gt;</kbd>: Подтвердить
<kbd>&lt;esc&gt;</kbd>: Закрыть/отменить
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Подтвердить | |
| `` <esc> `` | Закрыть/отменить | |
## Подкоммиты
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать SHA коммита в буфер обмена
<kbd>&lt;space&gt;</kbd>: Переключить коммит
<kbd>y</kbd>: Скопировать атрибут коммита
<kbd>o</kbd>: Открыть коммит в браузере
<kbd>n</kbd>: Создать новую ветку с этого коммита
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
<kbd>&lt;c-r&gt;</kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
<kbd>&lt;enter&gt;</kbd>: Просмотреть файлы выбранного элемента
<kbd>/</kbd>: Найти
</pre>
| 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 `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Найти | |
## Подмодули
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать название подмодуля в буфер обмена
<kbd>&lt;enter&gt;</kbd>: Ввести подмодуль
<kbd>d</kbd>: Удалить подмодуль
<kbd>u</kbd>: Обновить подмодуль
<kbd>n</kbd>: Добавить новый подмодуль
<kbd>e</kbd>: Обновить URL подмодуля
<kbd>i</kbd>: Инициализировать подмодуль
<kbd>b</kbd>: Просмотреть параметры массового подмодуля
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать название подмодуля в буфер обмена | |
| `` <enter> `` | Enter | Ввести подмодуль |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | Обновить подмодуль |
| `` n `` | Добавить новый подмодуль | |
| `` e `` | Обновить URL подмодуля | |
| `` i `` | Initialize | Инициализировать подмодуль |
| `` b `` | Просмотреть параметры массового подмодуля | |
| `` / `` | Filter the current view by text | |
## Сводка коммита
<pre>
<kbd>&lt;enter&gt;</kbd>: Подтвердить
<kbd>&lt;esc&gt;</kbd>: Закрыть
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | Подтвердить | |
| `` <esc> `` | Закрыть | |
## Сохранить Изменения Файлов
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать закомиченное имя файла в буфер обмена
<kbd>c</kbd>: Переключить файл
<kbd>d</kbd>: Отменить изменения коммита в этом файле
<kbd>o</kbd>: Открыть файл
<kbd>e</kbd>: Редактировать файл
<kbd>&lt;space&gt;</kbd>: Переключить файлы включённые в патч
<kbd>a</kbd>: Переключить все файлы, включённые в патч
<kbd>&lt;enter&gt;</kbd>: Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения)
<kbd>`</kbd>: Переключить вид дерева файлов
<kbd>/</kbd>: Найти
</pre>
| 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 `` | Переключить все файлы, включённые в патч | 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. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | Найти | |
## Статус
<pre>
<kbd>o</kbd>: Открыть файл конфигурации
<kbd>e</kbd>: Редактировать файл конфигурации
<kbd>u</kbd>: Проверить обновления
<kbd>&lt;enter&gt;</kbd>: Переключиться на последний репозиторий
<kbd>a</kbd>: Показать все логи ветки
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | Открыть файл конфигурации | Open file in default application. |
| `` e `` | Редактировать файл конфигурации | Open file in external editor. |
| `` u `` | Проверить обновления | |
| `` <enter> `` | Переключиться на последний репозиторий | |
| `` a `` | Показать все логи ветки | |
## Теги
<pre>
<kbd>&lt;space&gt;</kbd>: Переключить
<kbd>d</kbd>: Удалить тег
<kbd>P</kbd>: Отправить тег
<kbd>n</kbd>: Создать тег
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>&lt;enter&gt;</kbd>: Просмотреть коммиты
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` 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. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Удалённые ветки
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать название ветки в буфер обмена
<kbd>&lt;space&gt;</kbd>: Переключить
<kbd>n</kbd>: Новая ветка
<kbd>M</kbd>: Слияние с текущей переключённой веткой
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
<kbd>d</kbd>: Удалить ветку
<kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
<kbd>g</kbd>: Просмотреть параметры сброса
<kbd>&lt;enter&gt;</kbd>: Просмотреть коммиты
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать название ветки в буфер обмена | |
| `` <space> `` | Переключить | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | Новая ветка | |
| `` 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. |
| `` d `` | Delete | Delete the remote branch from the remote. |
| `` u `` | Set as upstream | Установить как upstream-ветку переключённую ветку |
| `` s `` | Порядок сортировки | |
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Удалённые репозитории
<pre>
<kbd>f</kbd>: Получение изменения из удалённого репозитория
<kbd>n</kbd>: Добавить новую удалённую ветку
<kbd>d</kbd>: Удалить удалённую ветку
<kbd>e</kbd>: Редактировать удалённый репозитории
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | Добавить новую удалённую ветку | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | Edit | Редактировать удалённый репозитории |
| `` f `` | Получить изменения | Получение изменения из удалённого репозитория |
| `` / `` | Filter the current view by text | |
## Файлы
<pre>
<kbd>&lt;c-o&gt;</kbd>: Скопировать название файла в буфер обмена
<kbd>d</kbd>: Просмотреть параметры «отмены изменении»
<kbd>&lt;space&gt;</kbd>: Переключить индекс
<kbd>&lt;c-b&gt;</kbd>: Фильтровать файлы (проиндексированные/непроиндексированные)
<kbd>c</kbd>: Сохранить изменения
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
<kbd>A</kbd>: Правка последнего коммита
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
<kbd>e</kbd>: Редактировать файл
<kbd>o</kbd>: Открыть файл
<kbd>i</kbd>: Игнорировать или исключить файл
<kbd>r</kbd>: Обновить файлы
<kbd>s</kbd>: Припрятать все изменения
<kbd>S</kbd>: Просмотреть параметры хранилища
<kbd>a</kbd>: Все проиндексированные/непроиндексированные
<kbd>&lt;enter&gt;</kbd>: Проиндексировать отдельные части/строки для файла или свернуть/развернуть для каталога
<kbd>g</kbd>: Просмотреть параметры сброса upstream-ветки
<kbd>D</kbd>: Просмотреть параметры сброса
<kbd>`</kbd>: Переключить вид дерева файлов
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
<kbd>f</kbd>: Получить изменения
<kbd>/</kbd>: Найти
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать название файла в буфер обмена | |
| `` <space> `` | Переключить индекс | Toggle staged for selected file. |
| `` <c-b> `` | Фильтровать файлы (проиндексированные/непроиндексированные) | |
| `` y `` | Copy to clipboard | |
| `` c `` | Сохранить изменения | Commit staged changes. |
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
| `` A `` | Правка последнего коммита | |
| `` 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> |
| `` e `` | Edit | Open file in external editor. |
| `` o `` | Открыть файл | Open file in default application. |
| `` i `` | Игнорировать или исключить файл | |
| `` r `` | Обновить файлы | |
| `` s `` | Stash | 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). |
| `` 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. |
| `` d `` | Просмотреть параметры «отмены изменении» | View options for discarding changes to the selected file. |
| `` g `` | Просмотреть параметры сброса upstream-ветки | |
| `` D `` | Reset | 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. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` M `` | Открыть внешний инструмент слияния (git mergetool) | Run `git mergetool`. |
| `` 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 |
| `` / `` | Найти | |
## Хранилище
<pre>
<kbd>&lt;space&gt;</kbd>: Применить припрятанные изменения
<kbd>g</kbd>: Применить припрятанные изменения и тут же удалить их из хранилища
<kbd>d</kbd>: Удалить припрятанные изменения из хранилища
<kbd>n</kbd>: Новая ветка
<kbd>r</kbd>: Переименовать хранилище
<kbd>&lt;enter&gt;</kbd>: Просмотреть файлы выбранного элемента
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | Применить припрятанные изменения | Apply the stash entry to your working directory. |
| `` g `` | Применить припрятанные изменения и тут же удалить их из хранилища | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | Удалить припрятанные изменения из хранилища | Remove the stash entry from the stash list. |
| `` 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 `` | Переименовать хранилище | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |

View File

@@ -1,333 +1,374 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit 按键绑定
_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_
## 全局键绑定
<pre>
<kbd>&lt;c-r&gt;</kbd>: 切换到最近的仓库
<kbd>&lt;pgup&gt;</kbd>: 向上滚动主面板 (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: 向下滚动主面板 (fn+down/shift+j)
<kbd>@</kbd>: 打开命令日志菜单
<kbd>}</kbd>: 扩大差异视图中显示的上下文范围
<kbd>{</kbd>: 缩小差异视图中显示的上下文范围
<kbd>:</kbd>: 执行自定义命令
<kbd>&lt;c-p&gt;</kbd>: 查看自定义补丁选项
<kbd>m</kbd>: 查看 合并/变基 选项
<kbd>R</kbd>: 刷新
<kbd>+</kbd>: 下一屏模式(正常/半屏/全屏)
<kbd>_</kbd>: 上一屏模式
<kbd>?</kbd>: 打开菜单
<kbd>&lt;c-s&gt;</kbd>: 查看按路径过滤选项
<kbd>W</kbd>: 打开 diff 菜单
<kbd>&lt;c-e&gt;</kbd>: 打开 diff 菜单
<kbd>&lt;c-w&gt;</kbd>: 切换是否在差异视图中显示空白字符差异
<kbd>z</kbd>: (通过 reflog撤销「实验功能」
<kbd>&lt;c-z&gt;</kbd>: (通过 reflog重做「实验功能」
<kbd>P</kbd>: 推送
<kbd>p</kbd>: 拉取
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | 切换到最近的仓库 | |
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
| `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 |
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,你可以在弹窗中配置上游分支。 |
| `` 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. |
| `` } `` | 扩大差异视图中显示的上下文范围 | 增加diff视图中围绕更改显示的上下文数量 |
| `` { `` | 缩小差异视图中显示的上下文范围 | 减少diff视图中围绕更改显示的上下文数量 |
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
| `` <c-p> `` | 查看自定义补丁选项 | |
| `` m `` | 查看 合并/变基 选项 | 查看当前合并或变基的中止、继续、跳过选项 |
| `` R `` | 刷新 | 刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch` |
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
| `` _ `` | 上一屏模式 | |
| `` ? `` | 打开菜单 | |
| `` <c-s> `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 |
| `` W `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref然后反转比较方向。 |
| `` <c-e> `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref然后反转比较方向。 |
| `` q `` | 退出 | |
| `` <esc> `` | 取消 | |
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | 切换是否在diff视图中显示空白更改 |
| `` z `` | (通过 reflog)撤销「实验功能」 | Reflog将用于确定运行哪个git命令来撤消最后一个git命令。这并不包括对工作树的更改只考虑提交。 |
| `` <c-z> `` | (通过 reflog)重做「实验功能」 | Reflog将用于确定运行哪个git命令来重做上一个git命令。这并不包括对工作树的更改只考虑提交。 |
## 列表面板导航
<pre>
<kbd>,</kbd>: 上一页
<kbd>.</kbd>: 下一页
<kbd>&lt;</kbd>: 滚动到顶部
<kbd>&gt;</kbd>: 滚动到底部
<kbd>/</kbd>: 开始搜索
<kbd>H</kbd>: 向左滚动
<kbd>L</kbd>: 向右滚动
<kbd>]</kbd>: 下一个标签
<kbd>[</kbd>: 上一个标签
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | 上一页 | |
| `` . `` | 下一页 | |
| `` < `` | 滚动到顶部 | |
| `` > `` | 滚动到底部 | |
| `` v `` | 切换拖动选择 | |
| `` <s-down> `` | 向下扩展选择范围 | |
| `` <s-up> `` | 向上扩展选择范围 | |
| `` / `` | 开始搜索 | |
| `` H `` | 向左滚动 | |
| `` L `` | 向右滚动 | |
| `` ] `` | 下一个标签 | |
| `` [ `` | 上一个标签 | |
## Reflog 页面
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将提交的 SHA 复制到剪贴板
<kbd>&lt;space&gt;</kbd>: 检出提交
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: 在浏览器中打开提交
<kbd>n</kbd>: 从提交创建新分支
<kbd>g</kbd>: 查看重置选项
<kbd>c</kbd>: 复制提交(拣选)
<kbd>C</kbd>: 复制提交范围(拣选)
<kbd>&lt;c-r&gt;</kbd>: 重置已拣选复制的提交
<kbd>&lt;enter&gt;</kbd>: 查看提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如hash、URL、diff、消息、作者)。 |
| `` o `` | 在浏览器中打开提交 | |
| `` n `` | 从提交创建新分支 | |
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 分支页面
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将分支名称复制到剪贴板
<kbd>i</kbd>: 显示 git-flow 选项
<kbd>&lt;space&gt;</kbd>: 检出
<kbd>n</kbd>: 新分支
<kbd>o</kbd>: 创建抓取请求
<kbd>O</kbd>: 创建取请求选项
<kbd>&lt;c-y&gt;</kbd>: 将抓取请求 URL 复制到剪贴板
<kbd>c</kbd>: 按名称检出
<kbd>F</kbd>: 强制检出
<kbd>d</kbd>: 删除分支
<kbd>r</kbd>: 将已检出的分支变基到该分支
<kbd>M</kbd>: 合并到当前检出的分支
<kbd>f</kbd>: 从上游快进此分支
<kbd>T</kbd>: 创建标签
<kbd>g</kbd>: 查看重置选项
<kbd>R</kbd>: 重命名分支
<kbd>u</kbd>: Set/Unset upstream
<kbd>&lt;enter&gt;</kbd>: 查看提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
| `` i `` | 显示 git-flow 选项 | |
| `` <space> `` | 检出 | 检出选中的项目 |
| `` n `` | 新分支 | |
| `` o `` | 创建取请求 | |
| `` O `` | 创建拉取请求选项 | |
| `` <c-y> `` | 将拉取请求 URL 复制到剪贴板 | |
| `` c `` | 按名称检出 | 按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。 |
| `` F `` | 强制检出 | 强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。 |
| `` d `` | 删除 | 查看本地/远程分支的删除选项 |
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
| `` f `` | 从上游快进此分支 | 将当前分支直接移动到远程追踪分支的最新提交 |
| `` T `` | 创建标签 | |
| `` s `` | 排序 | |
| `` g `` | 查看重置选项 | |
| `` R `` | 重命名分支 | |
| `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 子提交
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将提交的 SHA 复制到剪贴板
<kbd>&lt;space&gt;</kbd>: 检出提交
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: 在浏览器中打开提交
<kbd>n</kbd>: 从提交创建新分支
<kbd>g</kbd>: 查看重置选项
<kbd>c</kbd>: 复制提交(拣选)
<kbd>C</kbd>: 复制提交范围(拣选)
<kbd>&lt;c-r&gt;</kbd>: 重置已拣选复制的提交
<kbd>&lt;enter&gt;</kbd>: 查看提交的文件
<kbd>/</kbd>: 开始搜索
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如hash、URL、diff、消息、作者)。 |
| `` o `` | 在浏览器中打开提交 | |
| `` n `` | 从提交创建新分支 | |
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 开始搜索 | |
## 子模块
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将子模块名称复制到剪贴板
<kbd>&lt;enter&gt;</kbd>: 输入子模块
<kbd>d</kbd>: 删除子模块
<kbd>u</kbd>: 更新子模块
<kbd>n</kbd>: 添加新的子模块
<kbd>e</kbd>: 更新子模块 URL
<kbd>i</kbd>: 初始化子模块
<kbd>b</kbd>: 查看批量子模块选项
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
| `` <enter> `` | 进入 | 输入子模块 |
| `` d `` | 删除 | 删除选定的子模块及其相应的目录 |
| `` u `` | 更新 | 更新子模块 |
| `` n `` | 添加新的子模块 | |
| `` e `` | 更新子模块 URL | |
| `` i `` | 初始化 | 初始化子模块 |
| `` b `` | 查看批量子模块选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 工作区
| Key | Action | Info |
|-----|--------|-------------|
| `` n `` | 新建工作树 | |
| `` <space> `` | 切换 | 切换到选中的工作树 |
| `` o `` | 在编辑器中编写 | |
| `` d `` | 删除 | 删除选定的工作树。这将删除工作树的目录以及 .git 目录中有关工作树的元数据。 |
| `` / `` | 通过文本过滤当前视图 | |
## 提交
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将提交的 SHA 复制到剪贴板
<kbd>&lt;c-r&gt;</kbd>: 重置已拣选(复制)的提交
<kbd>b</kbd>: 查看二分查找选项
<kbd>s</kbd>: 向下压缩
<kbd>f</kbd>: 修正提交fixup
<kbd>r</kbd>: 改写提交
<kbd>R</kbd>: 使用编辑器重命名提交
<kbd>d</kbd>: 删除提交
<kbd>e</kbd>: 编辑提交
<kbd>p</kbd>: 选择提交(变基过程中)
<kbd>F</kbd>: 创建修正提交
<kbd>S</kbd>: 压缩在所选提交之上的所有“fixup!”提交(自动压缩)
<kbd>&lt;c-j&gt;</kbd>: 下移提交
<kbd>&lt;c-k&gt;</kbd>: 上移提交
<kbd>v</kbd>: 粘贴提交(拣选)
<kbd>A</kbd>: 用已暂存的更改来修补提交
<kbd>a</kbd>: Set/Reset commit author
<kbd>t</kbd>: 还原提交
<kbd>T</kbd>: 标签提交
<kbd>&lt;c-l&gt;</kbd>: 打开日志菜单
<kbd>&lt;space&gt;</kbd>: 检出提交
<kbd>y</kbd>: Copy commit attribute
<kbd>o</kbd>: 在浏览器中打开提交
<kbd>n</kbd>: 从提交创建新分支
<kbd>g</kbd>: 查看重置选项
<kbd>c</kbd>: 复制提交(拣选)
<kbd>C</kbd>: 复制提交范围(拣选)
<kbd>&lt;enter&gt;</kbd>: 查看提交的文件
<kbd>/</kbd>: 开始搜索
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` b `` | 查看二分查找选项 | |
| `` s `` | 压缩(Squash) | 将已选提交压缩到该提交之下。这些选定的提交的消息会附加到该提交的消息之下。 |
| `` f `` | 修正(fixup) | 将选定的提交合并到其下面的提交中。与压缩类似,但所选提交的消息将被丢弃。 |
| `` r `` | 改写提交 | 重写所选提交的消息。 |
| `` R `` | 使用编辑器重命名提交 | |
| `` d `` | 删除提交 | 删除选中的提交。这将通过变基从分支中删除该提交,如果该提交修改的内容依赖于后续的提交,则需要解决合并冲突。 |
| `` e `` | 编辑(开始交互式变基) | 编辑提交 |
| `` i `` | 开始交互式变基 | 为分支上的提交启动交互式变基。这将包括从 HEAD 提交到第一个合并提交或主分支提交的所有提交。
如果您想从所选提交启动交互式变基,请按 `e`。 |
| `` p `` | 拣选(Pick) | 选择提交(变基过程中) |
| `` F `` | 为此提交创建修正 | 创建修正提交 |
| `` S `` | 应用该修复提交 | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
| `` <c-j> `` | 下移提交 | |
| `` <c-k> `` | 上移提交 | |
| `` V `` | 粘贴提交(拣选) | |
| `` B `` | 标记一个主提交用于变基 | 选择下一次变基的主提交。当您变基到一个分支时只有高于主提交的提交才会被引入。这使用“git rebase --onto”命令。 |
| `` A `` | 修补(Amend) | 用已暂存的变更来修补提交 |
| `` a `` | 修补提交属性 | 设置或重置提交的作者,或添加其他作者。 |
| `` t `` | 撤销(Revert) | 为所选提交创建还原提交,这会反向应用所选提交的更改。 |
| `` T `` | 标签提交 | 创建一个新标签指向所选提交。你可以在弹窗中输入标签名称和描述(可选)。 |
| `` <c-l> `` | 打开日志菜单 | 查看提交日志的选项,例如更改排序顺序、隐藏 git graph、显示整个 git graph。 |
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如hash、URL、diff、消息、作者)。 |
| `` o `` | 在浏览器中打开提交 | |
| `` n `` | 从提交创建新分支 | |
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 开始搜索 | |
## 提交信息
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 确认 | |
| `` <esc> `` | 关闭 | |
## 提交文件
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将提交的文件名复制到剪贴板
<kbd>c</kbd>: 检出文件
<kbd>d</kbd>: 放弃对此文件的提交更改
<kbd>o</kbd>: 打开文件
<kbd>e</kbd>: 编辑文件
<kbd>&lt;space&gt;</kbd>: 补丁中包含的切换文件
<kbd>a</kbd>: Toggle all files included in patch
<kbd>&lt;enter&gt;</kbd>: 输入文件以将所选行添加到补丁中(或切换目录折叠)
<kbd>`</kbd>: 切换文件树视图
<kbd>/</kbd>: 开始搜索
</pre>
## 提交讯息
<pre>
<kbd>&lt;enter&gt;</kbd>: 确认
<kbd>&lt;esc&gt;</kbd>: 关闭
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
| `` 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 |
| `` / `` | 开始搜索 | |
## 文件
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将文件名复制到剪贴板
<kbd>d</kbd>: 查看'放弃更改'选项
<kbd>&lt;space&gt;</kbd>: 切换暂存状态
<kbd>&lt;c-b&gt;</kbd>: Filter files by status
<kbd>c</kbd>: 提交更改
<kbd>w</kbd>: 提交更改而无需预先提交钩子
<kbd>A</kbd>: 修补最后一次提交
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
<kbd>e</kbd>: 编辑文件
<kbd>o</kbd>: 打开文件
<kbd>i</kbd>: 忽略文件
<kbd>r</kbd>: 刷新文件
<kbd>s</kbd>: 将所有更改加入贮藏
<kbd>S</kbd>: 查看贮藏选项
<kbd>a</kbd>: 切换所有文件的暂存状态
<kbd>&lt;enter&gt;</kbd>: 暂存单个 块/行 用于文件, 或 折叠/展开 目录
<kbd>g</kbd>: 查看上游重置选项
<kbd>D</kbd>: 查看重置选项
<kbd>`</kbd>: 切换文件树视图
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
<kbd>f</kbd>: 抓取
<kbd>/</kbd>: 开始搜索
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将文件名复制到剪贴板 | |
| `` <space> `` | 切换暂存状态 | 为选定的文件切换暂存状态 |
| `` <c-b> `` | 通过状态过滤文件 | |
| `` y `` | 复制到剪贴板 | |
| `` c `` | 提交变更 | 提交暂存文件 |
| `` w `` | 提交变更而无需预先提交钩子 | |
| `` A `` | 修补最后一次提交 | |
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` e `` | 编辑 | 使用外部编辑器打开文件 |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` i `` | 忽略文件 | |
| `` r `` | 刷新文件 | |
| `` s `` | 贮藏 | 贮藏所有变更.若要使用其他贮藏变体,请使用查看贮藏选项快捷键 |
| `` S `` | 查看贮藏选项 | 查看贮藏选项(例如:贮藏所有、贮藏已暂存变更、贮藏未暂存变更) |
| `` a `` | 切换所有文件的暂存状态 | 切换工作区中所有文件的已暂存/未暂存状态 |
| `` <enter> `` | 暂存单个 块/行 用于文件, 或 折叠/展开 目录 | 如果选中的是一个文件,则会进入到暂存视图,以便可以暂存单个代码块/行。如果选中的是一个目录,则会折叠/展开这个目录 |
| `` d `` | 查看'放弃变更'选项 | 查看选中文件的放弃变更选项 |
| `` g `` | 查看上游重置选项 | |
| `` D `` | 重置 | 查看工作树的重置选项(例如:清除工作树)。 |
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
| `` f `` | 抓取 | 从远程获取变更 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 开始搜索 | |
## 构建补丁中
<pre>
<kbd>&lt;left&gt;</kbd>: 选择上一个区块
<kbd>&lt;right&gt;</kbd>: 选择一个区块
<kbd>v</kbd>: 切换拖动选择
<kbd>V</kbd>: 切换拖动选择
<kbd>a</kbd>: 切换选择区块
<kbd>&lt;c-o&gt;</kbd>: 将选中文本复制到剪贴板
<kbd>o</kbd>: 打开文件
<kbd>e</kbd>: 编辑文件
<kbd>&lt;space&gt;</kbd>: 添加/移除 行到补丁
<kbd>&lt;esc&gt;</kbd>: 退出逐行模式
<kbd>/</kbd>: 开始搜索
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 选择一个区块 | |
| `` <right> `` | 选择下一个区块 | |
| `` v `` | 切换拖动选择 | |
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` <space> `` | 添加/移除 行到补丁 | |
| `` <esc> `` | 退出逐行模式 | |
| `` / `` | 开始搜索 | |
## 标签页面
<pre>
<kbd>&lt;space&gt;</kbd>: 检出
<kbd>d</kbd>: 删除标签
<kbd>P</kbd>: 推送标签
<kbd>n</kbd>: 创建标签
<kbd>g</kbd>: 查看重置选项
<kbd>&lt;enter&gt;</kbd>: 查看提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy tag to clipboard | |
| `` <space> `` | 检出 | 检出选择的标签作为分离的HEAD |
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。 |
| `` d `` | 删除 | 查看本地/远程标签的删除选项 |
| `` P `` | 推送标签 | 推送选择的标签到远端。你将在弹窗中选择一个远端。 |
| `` g `` | 重置 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 正在合并
<pre>
<kbd>e</kbd>: 编辑文件
<kbd>o</kbd>: 打开文件
<kbd>&lt;left&gt;</kbd>: 选择上一个冲突
<kbd>&lt;right&gt;</kbd>: 选择下一个冲突
<kbd>&lt;up&gt;</kbd>: 选择部块
<kbd>&lt;down&gt;</kbd>: 选择底部块
<kbd>z</kbd>: 撤销
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
<kbd>&lt;space&gt;</kbd>: 选中区块
<kbd>b</kbd>: 选中所有区块
<kbd>&lt;esc&gt;</kbd>: 返回文件面板
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 选中区块 | |
| `` b `` | 选中所有区块 | |
| `` <up> `` | 选择顶部块 | |
| `` <down> `` | 选择部块 | |
| `` <left> `` | 选择上一个冲突 | |
| `` <right> `` | 选择下一个冲突 | |
| `` z `` | 撤销 | 撤消上次合并冲突解决 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
| `` <esc> `` | 返回文件面板 | |
## 正在暂存
<pre>
<kbd>&lt;left&gt;</kbd>: 选择上一个区块
<kbd>&lt;right&gt;</kbd>: 选择一个区块
<kbd>v</kbd>: 切换拖动选择
<kbd>V</kbd>: 切换拖动选择
<kbd>a</kbd>: 切换选择区块
<kbd>&lt;c-o&gt;</kbd>: 将选中文本复制到剪贴板
<kbd>o</kbd>: 打开文件
<kbd>e</kbd>: 编辑文件
<kbd>&lt;esc&gt;</kbd>: 返回文件面板
<kbd>&lt;tab&gt;</kbd>: 切换到其他面板
<kbd>&lt;space&gt;</kbd>: 切换行暂存状态
<kbd>d</kbd>: 取消变更 (git reset)
<kbd>E</kbd>: Edit hunk
<kbd>c</kbd>: 提交更改
<kbd>w</kbd>: 提交更而无需预先提交钩子
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息
<kbd>/</kbd>: 开始搜索
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 选择一个区块 | |
| `` <right> `` | 选择下一个区块 | |
| `` v `` | 切换拖动选择 | |
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时使用git reset丢弃该变更。当选择已暂存的变更时取消暂存该变更 |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` <esc> `` | 返回文件面板 | |
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
| `` E `` | 编辑代码块 | 在外部编辑器中编辑选中的代码块 |
| `` c `` | 提交变更 | 提交暂存文件 |
| `` w `` | 提交更而无需预先提交钩子 | |
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 开始搜索 | |
## 正常
<pre>
<kbd>mouse wheel down</kbd>: 向下滚动 (fn+up)
<kbd>mouse wheel up</kbd>:滚动 (fn+down)
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` |滚动 | |
| `` mouse wheel up (fn+down) `` | 向上滚动 | |
## 状态
<pre>
<kbd>o</kbd>: 打开配置文件
<kbd>e</kbd>: 编辑配置文件
<kbd>u</kbd>: 检查更新
<kbd>&lt;enter&gt;</kbd>: 切换到最近的仓库
<kbd>a</kbd>: 显示所有分支的日志
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | 打开配置文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑配置文件 | 使用外部编辑器打开文件 |
| `` u `` | 检查更新 | |
| `` <enter> `` | 切换到最近的仓库 | |
| `` a `` | 显示所有分支的日志 | |
## 确认面板
<pre>
<kbd>&lt;enter&gt;</kbd>: 确认
<kbd>&lt;esc&gt;</kbd>: 关闭
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 确认 | |
| `` <esc> `` | 关闭 | |
## 菜单
<pre>
<kbd>&lt;enter&gt;</kbd>: 执行
<kbd>&lt;esc&gt;</kbd>: 关闭
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 执行 | |
| `` <esc> `` | 关闭 | |
| `` / `` | 通过文本过滤当前视图 | |
## 贮藏
<pre>
<kbd>&lt;space&gt;</kbd>: 应用
<kbd>g</kbd>: 应用并删除
<kbd>d</kbd>: 删除
<kbd>n</kbd>: 新分支
<kbd>r</kbd>: Rename stash
<kbd>&lt;enter&gt;</kbd>: 查看提交的文件
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 应用 | 将贮藏项应用到您的工作目录。 |
| `` g `` | 应用并删除 | 将存储项应用到工作目录并删除存储项。 |
| `` d `` | 删除 | 从贮藏列表中删除该贮藏项 |
| `` n `` | 新分支 | 从选定的贮藏项创建一个新分支。这是通过 git 检查创建贮藏项的提交,从该提交创建一个新分支,然后将贮藏项作为附加提交应用到新分支来实现的。 |
| `` r `` | 重命名贮藏 | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 远程分支
<pre>
<kbd>&lt;c-o&gt;</kbd>: 将分支名称复制到剪贴板
<kbd>&lt;space&gt;</kbd>: 检出
<kbd>n</kbd>: 新分支
<kbd>M</kbd>: 合并到当前检出的分支
<kbd>r</kbd>: 将已检出的分支变基到该分支
<kbd>d</kbd>: 删除分支
<kbd>u</kbd>: 设置为检出分支的上游
<kbd>g</kbd>: 查看重置选项
<kbd>&lt;enter&gt;</kbd>: 查看提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
| `` <space> `` | 检出 | 基于当前选中的远程分支检出一个新的本地分支或者将远程分支作分离的HEAD。 |
| `` n `` | 新分支 | |
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
| `` d `` | 删除 | 从远程删除远程分支。 |
| `` u `` | 设置为上游 | 设置为检出分支的上游 |
| `` s `` | 排序 | |
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 远程页面
<pre>
<kbd>f</kbd>: 抓取远程仓库
<kbd>n</kbd>: 添加新的远程仓库
<kbd>d</kbd>: 删除远程
<kbd>e</kbd>: 编辑远程仓库
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 查看分支 | |
| `` n `` | 添加新的远程仓库 | |
| `` d `` | 删除 | 删除选中的远程。从远程跟踪远程分支的任何本地分支都不会受到影响。 |
| `` e `` | 编辑 | 编辑远程仓库 |
| `` f `` | 抓取 | 抓取远程仓库 |
| `` / `` | 通过文本过滤当前视图 | |

View File

@@ -1,333 +1,374 @@
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go run scripts/cheatsheet/main.go generate` from the project root._
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
# Lazygit 鍵盤快捷鍵
_說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B`B`表示 Shift+B_
_說明:`<c-b>` 表示 CtrlB、`<a-b>` 表示 AltB`B`表示 ShiftB_
## 全快捷鍵
## 全快捷鍵
<pre>
<kbd>&lt;c-r&gt;</kbd>: 切換到最近使用的版本庫
<kbd>&lt;pgup&gt;</kbd>: 向上捲動主面板 (fn+up/shift+k)
<kbd>&lt;pgdown&gt;</kbd>: 向下捲動主面板 (fn+down/shift+j)
<kbd>@</kbd>: 開啟命令記錄選單
<kbd>}</kbd>: 增加差異檢視中顯示變更周圍上下文的大小
<kbd>{</kbd>: 減小差異檢視中顯示變更周圍上下文的大小
<kbd>:</kbd>: 執行自訂命令
<kbd>&lt;c-p&gt;</kbd>: 檢視自訂補丁選項
<kbd>m</kbd>: 查看合併/變基選項
<kbd>R</kbd>: 重新整理
<kbd>+</kbd>: 下一個螢幕模式(常規/半螢幕/全螢幕)
<kbd>_</kbd>: 上一個螢幕模式
<kbd>?</kbd>: 開啟選單
<kbd>&lt;c-s&gt;</kbd>: 檢視篩選路徑選項
<kbd>W</kbd>: 開啟差異比較選單
<kbd>&lt;c-e&gt;</kbd>: 開啟差異比較選單
<kbd>&lt;c-w&gt;</kbd>: 切換是否在差異檢視中顯示空格變更
<kbd>z</kbd>: 復原
<kbd>&lt;c-z&gt;</kbd>: 取消復原
<kbd>P</kbd>: 推送
<kbd>p</kbd>: 拉取
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-r> `` | 切換到最近使用的版本庫 | |
| `` <pgup> (fn+up/shift+k) `` | 向上捲動主面板 | |
| `` <pgdown> (fn+down/shift+j) `` | 向下捲動主面板 | |
| `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. |
| `` P `` | 推送 | 推送到遠端。如果沒有設定遠端,會開啟設定視窗。 |
| `` 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. |
| `` { `` | 減小差異檢視中顯示變更周圍上下文的大小 | 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> `` | 檢視自訂補丁選項 | |
| `` 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`. |
| `` + `` | 下一個螢幕模式(常規/半螢幕/全螢幕) | |
| `` _ `` | 上一個螢幕模式 | |
| `` ? `` | 開啟選單 | |
| `` <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. |
| `` <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 `` | 結束 | |
| `` <esc> `` | 取消 | |
| `` <c-w> `` | 切換是否在差異檢視中顯示空格變更 | Toggle whether or not whitespace changes are shown in the diff view. |
| `` z `` | 復原 | 將使用 reflog 確任 git 指令以復原。這不包括工作區更改;只考慮提交。 |
| `` <c-z> `` | 取消復原 | 將使用 reflog 確任 git 指令以重作。這不包括工作區更改;只考慮提交。 |
## 列表面板導航
## 移動
<pre>
<kbd>,</kbd>: 上一頁
<kbd>.</kbd>: 下一頁
<kbd>&lt;</kbd>: 捲動到頂部
<kbd>&gt;</kbd>: 捲動到底部
<kbd>/</kbd>: 開始搜尋
<kbd>H</kbd>: 向左捲動
<kbd>L</kbd>: 向右捲動
<kbd>]</kbd>: 下一個索引標籤
<kbd>[</kbd>: 上一個索引標籤
</pre>
## Reflog
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製提交 SHA 到剪貼簿
<kbd>&lt;space&gt;</kbd>: 檢出提交
<kbd>y</kbd>: 複製提交屬性
<kbd>o</kbd>: 在瀏覽器中開啟提交
<kbd>n</kbd>: 從提交建立新分支
<kbd>g</kbd>: 檢視重設選項
<kbd>c</kbd>: 複製提交 (揀選)
<kbd>C</kbd>: 複製提交範圍 (揀選)
<kbd>&lt;c-r&gt;</kbd>: 重設選定的揀選 (複製) 提交
<kbd>&lt;enter&gt;</kbd>: 檢視提交
<kbd>/</kbd>: Filter the current view by text
</pre>
## 主視窗 (一般)
<pre>
<kbd>mouse wheel down</kbd>: 向下捲動 (fn+up)
<kbd>mouse wheel up</kbd>: 向上捲動 (fn+down)
</pre>
## 主視窗 (合併中)
<pre>
<kbd>e</kbd>: 編輯檔案
<kbd>o</kbd>: 開啟檔案
<kbd>&lt;left&gt;</kbd>: 選擇上一個衝突
<kbd>&lt;right&gt;</kbd>: 選擇下一個衝突
<kbd>&lt;up&gt;</kbd>: 選擇上一段
<kbd>&lt;down&gt;</kbd>: 選擇下一段
<kbd>z</kbd>: 復原
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
<kbd>&lt;space&gt;</kbd>: 挑選程式碼片段
<kbd>b</kbd>: 挑選所有程式碼片段
<kbd>&lt;esc&gt;</kbd>: 返回檔案面板
</pre>
## 主視窗 (預存中)
<pre>
<kbd>&lt;left&gt;</kbd>: 選擇上一段
<kbd>&lt;right&gt;</kbd>: 選擇下一段
<kbd>v</kbd>: 切換拖曳選擇
<kbd>V</kbd>: 切換拖曳選擇
<kbd>a</kbd>: 切換選擇程式碼塊
<kbd>&lt;c-o&gt;</kbd>: 複製所選文本至剪貼簿
<kbd>o</kbd>: 開啟檔案
<kbd>e</kbd>: 編輯檔案
<kbd>&lt;esc&gt;</kbd>: 返回檔案面板
<kbd>&lt;tab&gt;</kbd>: 切換至另一個面板 (已預存/未預存更改)
<kbd>&lt;space&gt;</kbd>: 切換現有行的狀態 (已預存/未預存)
<kbd>d</kbd>: 刪除變更 (git reset)
<kbd>E</kbd>: 編輯程式碼塊
<kbd>c</kbd>: 提交變更
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
<kbd>C</kbd>: 使用 git 編輯器提交變更
<kbd>/</kbd>: 開始搜尋
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` , `` | 上一頁 | |
| `` . `` | 下一頁 | |
| `` < `` | 捲動到頂部 | |
| `` > `` | 捲動到底部 | |
| `` v `` | 切換拖曳選擇 | |
| `` <s-down> `` | Range select down | |
| `` <s-up> `` | Range select up | |
| `` / `` | 搜尋 | |
| `` H `` | 向左捲動 | |
| `` L `` | 向右捲動 | |
| `` ] `` | 下一個索引標籤 | |
| `` [ `` | 上一個索引標籤 | |
## 主面板 (補丁生成)
<pre>
<kbd>&lt;left&gt;</kbd>: 選擇上一段
<kbd>&lt;right&gt;</kbd>: 選擇一段
<kbd>v</kbd>: 切換拖曳選擇
<kbd>V</kbd>: 切換拖曳選擇
<kbd>a</kbd>: 切換選擇程式碼塊
<kbd>&lt;c-o&gt;</kbd>: 複製所選文本至剪貼簿
<kbd>o</kbd>: 開啟檔案
<kbd>e</kbd>: 編輯檔案
<kbd>&lt;space&gt;</kbd>: 向 (或從) 補丁中添加/刪除行
<kbd>&lt;esc&gt;</kbd>: 退出自訂補丁建立器
<kbd>/</kbd>: 開始搜尋
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <left> `` | 選擇一段 | |
| `` <right> `` | 選擇下一段 | |
| `` v `` | 切換拖曳選擇 | |
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
| `` <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> |
| `` / `` | 搜尋 | |
## 功能表
<pre>
<kbd>&lt;enter&gt;</kbd>: 執行
<kbd>&lt;esc&gt;</kbd>: 關閉
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 執行 | |
| `` <esc> `` | 關閉 | |
| `` / `` | 搜尋 | |
## 子提交
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製提交 SHA 到剪貼簿
<kbd>&lt;space&gt;</kbd>: 檢出提交
<kbd>y</kbd>: 複製提交屬性
<kbd>o</kbd>: 在瀏覽器中開啟提交
<kbd>n</kbd>: 從提交建立新分支
<kbd>g</kbd>: 檢視重設選項
<kbd>c</kbd>: 複製提交 (揀選)
<kbd>C</kbd>: 複製提交範圍 (揀選)
<kbd>&lt;c-r&gt;</kbd>: 重設選定的揀選 (複製) 提交
<kbd>&lt;enter&gt;</kbd>: 檢視所選項目的檔案
<kbd>/</kbd>: 開始搜尋
</pre>
| 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 `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 子模組
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製子模組名稱到剪貼簿
<kbd>&lt;enter&gt;</kbd>: 進入子模組
<kbd>d</kbd>: 移除子模組
<kbd>u</kbd>: 更新子模組
<kbd>n</kbd>: 新增子模組
<kbd>e</kbd>: 更新子模組 URL
<kbd>i</kbd>: 初始化子模組
<kbd>b</kbd>: 查看批量子模組選項
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製子模組名稱到剪貼簿 | |
| `` <enter> `` | Enter | 進入子模組 |
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
| `` u `` | Update | 更新子模組 |
| `` n `` | 新增子模組 | |
| `` e `` | 更新子模組 URL | |
| `` i `` | Initialize | 初始化子模組 |
| `` b `` | 查看批量子模組選項 | |
| `` / `` | 搜尋 | |
## 工作目錄
| 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. |
| `` / `` | 搜尋 | |
## 提交
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製提交 SHA 到剪貼簿
<kbd>&lt;c-r&gt;</kbd>: 重設選定的揀選 (複製) 提交
<kbd>b</kbd>: 查看二分選項
<kbd>s</kbd>: 向下壓縮
<kbd>f</kbd>: 修復提交 (Fixup)
<kbd>r</kbd>: 改寫提交
<kbd>R</kbd>: 使用編輯器改寫提交
<kbd>d</kbd>: 刪除提交
<kbd>e</kbd>: 編輯提交
<kbd>p</kbd>: 挑選提交 (於變基過程中)
<kbd>F</kbd>: 為此提交建立修復提交
<kbd>S</kbd>: 壓縮上方所有的“fixup!”提交 (自動壓縮)
<kbd>&lt;c-j&gt;</kbd>: 向下移動提交
<kbd>&lt;c-k&gt;</kbd>: 向上移動提交
<kbd>v</kbd>: 貼上提交 (揀選)
<kbd>A</kbd>: 使用已預存的更改修正提交
<kbd>a</kbd>: 設置/重設提交作者
<kbd>t</kbd>: 還原提交
<kbd>T</kbd>: 打標籤到提交
<kbd>&lt;c-l&gt;</kbd>: 開啟記錄選單
<kbd>&lt;space&gt;</kbd>: 檢出提交
<kbd>y</kbd>: 複製提交屬性
<kbd>o</kbd>: 在瀏覽器中開啟提交
<kbd>n</kbd>: 從提交建立新分支
<kbd>g</kbd>: 檢視重設選項
<kbd>c</kbd>: 複製提交 (揀選)
<kbd>C</kbd>: 複製提交範圍 (揀選)
<kbd>&lt;enter&gt;</kbd>: 檢視所選項目的檔案
<kbd>/</kbd>: 開始搜尋
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
| `` 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. |
| `` f `` | 修復 (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
| `` 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. |
| `` e `` | 編輯(開始互動變基) | 編輯提交 |
| `` 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`. |
| `` p `` | 挑選 | 挑選提交 (於變基過程中) |
| `` F `` | 建立修復提交 | 為此提交建立修復提交 |
| `` S `` | 壓縮上方所有「fixup」提交自動壓縮 | 是否壓縮上方 {{.commit}} 所有「fixup」提交 |
| `` <c-j> `` | 向下移動提交 | |
| `` <c-k> `` | 向上移動提交 | |
| `` V `` | 貼上提交 (揀選) | |
| `` B `` | 為了變基已標注提交為基準提交 | 請為了下一次變基選擇一項基準提交;此將執行 `git rebase --onto`。 |
| `` A `` | 修改 | 使用已預存的更改修正提交 |
| `` a `` | 設定/重設提交作者 | Set/Reset commit author or set co-author. |
| `` 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. |
| `` <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. |
| `` 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-t> `` | 開啟外部差異工具 (git difftool) | |
| `` <enter> `` | 檢視所選項目的檔案 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 提交摘要
<pre>
<kbd>&lt;enter&gt;</kbd>: 確認
<kbd>&lt;esc&gt;</kbd>: 關閉
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 確認 | |
| `` <esc> `` | 關閉 | |
## 提交檔案
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製提交的檔案名稱到剪貼簿
<kbd>c</kbd>: 檢出檔案
<kbd>d</kbd>: 捨棄此提交對此檔案的更改
<kbd>o</kbd>: 開啟檔案
<kbd>e</kbd>: 編輯檔案
<kbd>&lt;space&gt;</kbd>: 切換檔案是否包含在補丁中
<kbd>a</kbd>: 切換所有檔案是否包含在補丁中
<kbd>&lt;enter&gt;</kbd>: 輸入檔案以將選定的行添加至補丁(或切換目錄折疊)
<kbd>`</kbd>: 切換檔案樹狀視圖
<kbd>/</kbd>: 開始搜尋
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
| `` c `` | 檢出 | 檢出檔案 |
| `` 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 `` | 開啟檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯 | 使用外部編輯器開啟 |
| `` <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. |
| `` 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. |
| `` ` `` | 顯示檔案樹狀視圖 | 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)
<pre>
<kbd>&lt;space&gt;</kbd>: 套用
<kbd>g</kbd>: 還原
<kbd>d</kbd>: 捨棄
<kbd>n</kbd>: 新分支
<kbd>r</kbd>: 重新命名收藏
<kbd>&lt;enter&gt;</kbd>: 檢視所選項目的檔案
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <space> `` | 套用 | Apply the stash entry to your working directory. |
| `` g `` | 還原 | Apply the stash entry to your working directory and remove the stash entry. |
| `` d `` | 捨棄 | Remove the stash entry from the stash list. |
| `` 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 `` | 重新命名收藏 | |
| `` <enter> `` | 檢視所選項目的檔案 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 日誌
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製提交 hash 到剪貼簿 | |
| `` <space> `` | 檢出 | Checkout the selected commit as a detached HEAD. |
| `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | 在瀏覽器中開啟提交 | |
| `` n `` | 從提交建立新分支 | |
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 本地分支
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製分支名稱到剪貼簿
<kbd>i</kbd>: 顯示 git-flow 選項
<kbd>&lt;space&gt;</kbd>: 檢出
<kbd>n</kbd>: 新分支
<kbd>o</kbd>: 建立拉取請求
<kbd>O</kbd>: 建立拉取請求選項
<kbd>&lt;c-y&gt;</kbd>: 複製拉取請求的 URL 到剪貼板
<kbd>c</kbd>: 根據名稱檢出
<kbd>F</kbd>: 強制檢出
<kbd>d</kbd>: 刪除分支
<kbd>r</kbd>: 將已檢出的分支變基至此分支
<kbd>M</kbd>: 合併到當前檢出的分支
<kbd>f</kbd>: 從上游快進此分支
<kbd>T</kbd>: 建立標籤
<kbd>g</kbd>: 檢視重設選項
<kbd>R</kbd>: 重新命名分支
<kbd>u</kbd>: 設定/取消設定上游
<kbd>&lt;enter&gt;</kbd>: 檢視提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
| `` i `` | 顯示 git-flow 選項 | |
| `` <space> `` | 檢出 | 檢出選定的項目。 |
| `` n `` | 新分支 | |
| `` o `` | 建立拉取請求 | |
| `` O `` | 建立拉取請求選項 | |
| `` <c-y> `` | 複製拉取請求的 URL 到剪貼板 | |
| `` 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. |
| `` d `` | 刪除 | View delete options for local/remote branch. |
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
| `` f `` | 從上游快進此分支 | 從遠端快進所選的分支 |
| `` T `` | 建立標籤 | |
| `` s `` | 排序規則 | |
| `` g `` | 檢視重設選項 | |
| `` R `` | 重新命名分支 | |
| `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 標籤
<pre>
<kbd>&lt;space&gt;</kbd>: 檢出
<kbd>d</kbd>: 刪除標籤
<kbd>P</kbd>: 推送標籤
<kbd>n</kbd>: 建立標籤
<kbd>g</kbd>: 檢視重設選項
<kbd>&lt;enter&gt;</kbd>: 檢視提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <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. |
| `` d `` | 刪除 | View delete options for local/remote tag. |
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | 重設 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
## 檔案
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製檔案名稱到剪貼簿
<kbd>d</kbd>: 檢視“捨棄更改”的選項
<kbd>&lt;space&gt;</kbd>: 切換預存
<kbd>&lt;c-b&gt;</kbd>: 篩選檔案 (預存/未預存)
<kbd>c</kbd>: 提交變更
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
<kbd>A</kbd>: 修正上次提交
<kbd>C</kbd>: 使用 git 編輯器提交變更
<kbd>e</kbd>: 編輯檔案
<kbd>o</kbd>: 開啟檔案
<kbd>i</kbd>: 忽略或排除檔案
<kbd>r</kbd>: 重新整理檔案
<kbd>s</kbd>: 收藏所有變更
<kbd>S</kbd>: 檢視收藏選項
<kbd>a</kbd>: 全部預存/取消預存
<kbd>&lt;enter&gt;</kbd>: 選擇檔案中的單個程式碼塊/行,或展開/折疊目錄
<kbd>g</kbd>: 檢視上游重設選項
<kbd>D</kbd>: 檢視重設選項
<kbd>`</kbd>: 切換檔案樹狀視圖
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
<kbd>f</kbd>: 擷取
<kbd>/</kbd>: 開始搜尋
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
| `` <space> `` | 切換預存 | Toggle staged for selected file. |
| `` <c-b> `` | 篩選檔案 (預存/未預存) | |
| `` y `` | 複製到剪貼簿 | |
| `` c `` | 提交變更 | 提交暫存區變更 |
| `` w `` | 沒有預提交 hook 就提交更改 | |
| `` A `` | 修改上次提交 | |
| `` 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> |
| `` e `` | 編輯 | 使用外部編輯器開啟 |
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
| `` i `` | 忽略或排除檔案 | |
| `` r `` | 重新整理檔案 | |
| `` 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). |
| `` 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. |
| `` d `` | 捨棄 | 檢視選中變動進行捨棄復原 |
| `` g `` | 檢視遠端重設選項 | |
| `` 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. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
| `` f `` | 擷取 | 同步遠端異動 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` / `` | 搜尋 | |
## 狀態
<pre>
<kbd>o</kbd>: 開啟設定檔案
<kbd>e</kbd>: 編輯設定檔案
<kbd>u</kbd>: 檢查更新
<kbd>&lt;enter&gt;</kbd>: 切換到最近使用的版本庫
<kbd>a</kbd>: 顯示所有分支日誌
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` o `` | 開啟設定檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯設定檔案 | 使用外部編輯器開啟 |
| `` u `` | 檢查更新 | |
| `` <enter> `` | 切換到最近使用的版本庫 | |
| `` a `` | 顯示所有分支日誌 | |
## 確認面板
<pre>
<kbd>&lt;enter&gt;</kbd>: 確認
<kbd>&lt;esc&gt;</kbd>: 關閉/取消
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | 確認 | |
| `` <esc> `` | 關閉/取消 | |
## 遠端
<pre>
<kbd>f</kbd>: 擷取遠端
<kbd>n</kbd>: 新增遠端
<kbd>d</kbd>: 移除遠端
<kbd>e</kbd>: 編輯遠端
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <enter> `` | View branches | |
| `` n `` | 新增遠端 | |
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
| `` e `` | 編輯 | 編輯遠端 |
| `` f `` | 擷取 | 擷取遠端 |
| `` / `` | 搜尋 | |
## 遠端分支
<pre>
<kbd>&lt;c-o&gt;</kbd>: 複製分支名稱到剪貼簿
<kbd>&lt;space&gt;</kbd>: 檢出
<kbd>n</kbd>: 新分支
<kbd>M</kbd>: 合併到當前檢出的分支
<kbd>r</kbd>: 將已檢出的分支變基至此分支
<kbd>d</kbd>: 刪除分支
<kbd>u</kbd>: 將此分支設為當前分支之上游
<kbd>g</kbd>: 檢視重設選項
<kbd>&lt;enter&gt;</kbd>: 檢視提交
<kbd>/</kbd>: Filter the current view by text
</pre>
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
| `` <space> `` | 檢出 | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
| `` n `` | 新分支 | |
| `` 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. |
| `` d `` | 刪除 | Delete the remote branch from the remote. |
| `` u `` | 設置為遠端 | 將此分支設為當前分支之遠端 |
| `` s `` | 排序規則 | |
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |

53
go.mod
View File

@@ -1,74 +1,81 @@
module github.com/jesseduffield/lazygit
go 1.18
go 1.22
require (
github.com/OpenPeeDeeP/xdg v1.0.0
github.com/adrg/xdg v0.4.0
github.com/atotto/clipboard v0.1.4
github.com/aybabtme/humanlog v0.4.1
github.com/cli/safeexec v1.0.0
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/creack/pty v1.1.11
github.com/fsmiamoto/git-todo-parser v0.0.5
github.com/fsnotify/fsnotify v1.4.7
github.com/gdamore/tcell/v2 v2.6.0
github.com/go-errors/errors v1.4.2
github.com/gdamore/tcell/v2 v2.8.1
github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2
github.com/iancoleman/orderedmap v0.3.0
github.com/imdario/mergo v0.3.11
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20230719120401-398f4965241f
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/gocui v0.3.1-0.20250210123912-aba68ae65951
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3
github.com/kyokomi/emoji/v2 v2.2.8
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/mattn/go-runewidth v0.0.14
github.com/mattn/go-runewidth v0.0.16
github.com/mgutz/str v1.2.0
github.com/pmezard/go-difflib v1.0.0
github.com/mitchellh/go-ps v1.0.0
github.com/sahilm/fuzzy v0.1.0
github.com/samber/lo v1.31.0
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/spf13/afero v1.9.5
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
github.com/stretchr/testify v1.8.0
github.com/stefanhaller/git-todo-parser v0.0.7-0.20240406123903-fd957137b6e2
github.com/stretchr/testify v1.8.1
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778
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/yaml.v3 v3.0.1
)
require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emirpasic/gods v1.12.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/go-billy/v5 v5.0.0 // indirect
github.com/go-logfmt/logfmt v0.5.0 // 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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

541
go.sum
View File

@@ -1,5 +1,45 @@
github.com/OpenPeeDeeP/xdg v1.0.0 h1:UDLmNjCGFZZCaVMB74DqYEtXkHxnTxcr4FeJVF9uCn8=
github.com/OpenPeeDeeP/xdg v1.0.0/go.mod h1:tMoSueLQlMf0TCldjrJLNIjAc5qAOIcHt5REi88/Ygo=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
@@ -11,10 +51,20 @@ github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn
github.com/aybabtme/humanlog v0.4.1 h1:D8d9um55rrthJsP8IGSHBcti9lTb/XknmDAX6Zy8tek=
github.com/aybabtme/humanlog v0.4.1/go.mod h1:B0bnQX4FTSU3oftPMTTPvENCy8LqixLDvYJA9TUCAGo=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -24,70 +74,143 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
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/fsmiamoto/git-todo-parser v0.0.5 h1:Bhzd/vz/6Qm3udfkd6NO9fWfD3TpwR9ucp3N75/J5I8=
github.com/fsmiamoto/git-todo-parser v0.0.5/go.mod h1:B+AgTbNE2BARvJqzXygThzqxLIaEWvwr2sxKYYb0Fas=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.6.0 h1:OKbluoP9VYmJwZwq/iLb4BxwKcwGthaa1YNBJIyCySg=
github.com/gdamore/tcell/v2 v2.6.0/go.mod h1:be9omFATkdr0D9qewWW3d+MEvl5dha+Etb5y65J2H8Y=
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.8.0/go.mod h1:bj8ori1BG3OYMjmb3IklZVWfZUJ1UBQt9JXrOCOhGWw=
github.com/gdamore/tcell/v2 v2.8.1 h1:KPNxyqclpWpWQlPLx6Xui1pMk8S+7+R37h3g07997NU=
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/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
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/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM=
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
github.com/invopop/jsonschema v0.10.0 h1:c1ktzNLBun3LyQQhyty5WE3lulbOdIIyOVlkmDLehcE=
github.com/invopop/jsonschema v0.10.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8TIcC6Y4RI+1ZbJDOHfGJ570tPeYVCqo7/tws=
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/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/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20230719120401-398f4965241f h1:w/pxI34XepTAx4HwxUu8ipimbVRgSTS+7ahmgFQwH80=
github.com/jesseduffield/gocui v0.3.1-0.20230719120401-398f4965241f/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/gocui v0.3.1-0.20250210123912-aba68ae65951 h1:7/3M0yosAM9/aLAjTfzSJWhsWjT860ZVe4T76RPwE2k=
github.com/jesseduffield/gocui v0.3.1-0.20250210123912-aba68ae65951/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
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/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/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3 h1:s995u+gNQADMaixtNOs+jilRC/Q78q0UXSI7+4T0cDE=
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3/go.mod h1:MCbEh21gjOzxc31udr3u4QM9DAdf8TFJCZz3u5hYIxA=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -99,9 +222,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE=
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
@@ -111,13 +235,14 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
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/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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -125,112 +250,430 @@ 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/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
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/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw=
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.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
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/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/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.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.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 v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU=
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.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-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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-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.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.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-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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-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-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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
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.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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.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-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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 h1:KzcWKJ0nMAmGoBhYVMnkWc1rXjB42lKy5aIys4TdLOA=
@@ -246,3 +689,13 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -11,10 +11,9 @@ import (
"github.com/go-errors/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/jesseduffield/generics/slices"
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/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
@@ -23,6 +22,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/env"
"github.com/jesseduffield/lazygit/pkg/gui"
"github.com/jesseduffield/lazygit/pkg/i18n"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
"github.com/jesseduffield/lazygit/pkg/logs"
"github.com/jesseduffield/lazygit/pkg/updates"
)
@@ -42,7 +42,7 @@ func Run(
common *common.Common,
startArgs appTypes.StartArgs,
) {
app, err := NewApp(config, common)
app, err := NewApp(config, startArgs.IntegrationTest, common)
if err == nil {
err = app.Run(startArgs)
@@ -62,20 +62,21 @@ func Run(
func NewCommon(config config.AppConfigurer) (*common.Common, error) {
userConfig := config.GetUserConfig()
var err error
appState := config.GetAppState()
log := newLogger(config)
tr, err := i18n.NewTranslationSetFromConfig(log, userConfig.Gui.Language)
if err != nil {
return nil, err
}
// Initialize with English for the time being; the real translation set for
// the configured language will be read after reading the user config
tr := i18n.EnglishTranslationSet()
return &common.Common{
Log: log,
Tr: tr,
UserConfig: userConfig,
Debug: config.GetDebug(),
}, nil
cmn := &common.Common{
Log: log,
Tr: tr,
AppState: appState,
Debug: config.GetDebug(),
Fs: afero.NewOsFs(),
}
cmn.SetUserConfig(userConfig)
return cmn, nil
}
func newLogger(cfg config.AppConfigurer) *logrus.Entry {
@@ -91,7 +92,7 @@ func newLogger(cfg config.AppConfigurer) *logrus.Entry {
}
// NewApp bootstrap a new application
func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
func NewApp(config config.AppConfigurer, test integrationTypes.IntegrationTest, common *common.Common) (*App, error) {
app := &App{
closers: []io.Closer{},
Config: config,
@@ -115,7 +116,14 @@ func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
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 {
return app, err
}
@@ -125,7 +133,7 @@ func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
showRecentRepos = true
}
app.Gui, err = gui.NewGui(common, config, gitVersion, updater, showRecentRepos, dirName)
app.Gui, err = gui.NewGui(common, config, gitVersion, updater, showRecentRepos, dirName, test)
if err != nil {
return app, err
}
@@ -164,14 +172,16 @@ func openRecentRepo(app *App) bool {
return false
}
func (app *App) setupRepo() (bool, error) {
func (app *App) setupRepo(
repoPaths *git_commands.RepoPaths,
) (bool, error) {
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
}
// 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()
if err != nil {
return false, err
@@ -183,7 +193,7 @@ func (app *App) setupRepo() (bool, error) {
var shouldInitRepo bool
initialBranchArg := ""
switch app.UserConfig.NotARepository {
switch app.UserConfig().NotARepository {
case "prompt":
// Offer to initialize a new repository in current directory.
fmt.Print(app.Tr.CreateRepo)
@@ -217,6 +227,7 @@ func (app *App) setupRepo() (bool, error) {
if err := app.OSCommand.Cmd.New(args).Run(); err != nil {
return false, err
}
return false, nil
}
@@ -234,10 +245,7 @@ func (app *App) setupRepo() (bool, error) {
}
// 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 err != nil {
return false, err
}
if repoPaths.IsBareRepo() {
fmt.Print(app.Tr.BareRepo)
@@ -265,7 +273,11 @@ func (app *App) Run(startArgs appTypes.StartArgs) error {
// Close closes any resources
func (app *App) Close() error {
return slices.TryForEach(app.closers, func(closer io.Closer) error {
return closer.Close()
})
for _, closer := range app.closers {
if err := closer.Close(); err != nil {
return err
}
}
return nil
}

View File

@@ -5,12 +5,11 @@ import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
@@ -33,12 +32,15 @@ const (
DaemonKindUnknown DaemonKind = iota
DaemonKindExitImmediately
DaemonKindRemoveUpdateRefsForCopiedBranch
DaemonKindCherryPick
DaemonKindMoveTodoUp
DaemonKindMoveTodoDown
DaemonKindMoveTodosUp
DaemonKindMoveTodosDown
DaemonKindInsertBreak
DaemonKindChangeTodoActions
DaemonKindDropMergeCommit
DaemonKindMoveFixupCommitDown
DaemonKindWriteRebaseTodo
)
const (
@@ -52,13 +54,16 @@ func getInstruction() Instruction {
jsonData := os.Getenv(DaemonInstructionEnvKey)
mapping := map[DaemonKind]func(string) Instruction{
DaemonKindExitImmediately: deserializeInstruction[*ExitImmediatelyInstruction],
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
DaemonKindMoveTodoUp: deserializeInstruction[*MoveTodoUpInstruction],
DaemonKindMoveTodoDown: deserializeInstruction[*MoveTodoDownInstruction],
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
DaemonKindExitImmediately: deserializeInstruction[*ExitImmediatelyInstruction],
DaemonKindRemoveUpdateRefsForCopiedBranch: deserializeInstruction[*RemoveUpdateRefsForCopiedBranchInstruction],
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
DaemonKindDropMergeCommit: deserializeInstruction[*DropMergeCommitInstruction],
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
DaemonKindWriteRebaseTodo: deserializeInstruction[*WriteRebaseTodoInstruction],
}
return mapping[getDaemonKind()](jsonData)
@@ -92,7 +97,7 @@ func getDaemonKind() DaemonKind {
}
func getCommentChar() byte {
cmd := secureexec.Command("git", "config", "--get", "--null", "core.commentChar")
cmd := exec.Command("git", "config", "--get", "--null", "core.commentChar")
if output, err := cmd.Output(); err == nil && len(output) == 2 {
return output[0]
}
@@ -155,6 +160,26 @@ func NewExitImmediatelyInstruction() Instruction {
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 {
Todo string
}
@@ -208,28 +233,55 @@ func (self *ChangeTodoActionsInstruction) SerializedInstructions() string {
func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
return handleInteractiveRebase(common, func(path string) error {
for _, c := range self.Changes {
if err := utils.EditRebaseTodo(path, c.Sha, todo.Pick, c.NewAction, getCommentChar()); err != nil {
return err
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
return utils.TodoChange{
Hash: c.Hash,
NewAction: c.NewAction,
}
}
})
return nil
return utils.EditRebaseTodo(path, changes, getCommentChar())
})
}
// Takes the sha of some commit, and the sha of a fixup commit that was created
// at the end of the branch, then moves the fixup commit down to right after the
// original commit, changing its type to "fixup"
type MoveFixupCommitDownInstruction struct {
OriginalSha string
FixupSha string
type DropMergeCommitInstruction struct {
Hash 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{
OriginalSha: originalSha,
FixupSha: fixupSha,
OriginalHash: originalHash,
FixupHash: fixupHash,
ChangeToFixup: changeToFixup,
}
}
@@ -243,55 +295,67 @@ func (self *MoveFixupCommitDownInstruction) SerializedInstructions() string {
func (self *MoveFixupCommitDownInstruction) run(common *common.Common) 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 MoveTodoUpInstruction struct {
Sha string
type MoveTodosUpInstruction struct {
Hashes []string
}
func NewMoveTodoUpInstruction(sha string) Instruction {
return &MoveTodoUpInstruction{
Sha: sha,
func NewMoveTodosUpInstruction(hashes []string) Instruction {
return &MoveTodosUpInstruction{
Hashes: hashes,
}
}
func (self *MoveTodoUpInstruction) Kind() DaemonKind {
return DaemonKindMoveTodoUp
func (self *MoveTodosUpInstruction) Kind() DaemonKind {
return DaemonKindMoveTodosUp
}
func (self *MoveTodoUpInstruction) SerializedInstructions() string {
func (self *MoveTodosUpInstruction) SerializedInstructions() string {
return serializeInstruction(self)
}
func (self *MoveTodoUpInstruction) run(common *common.Common) error {
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
return utils.Todo{
Hash: hash,
}
})
return handleInteractiveRebase(common, func(path string) error {
return utils.MoveTodoUp(path, self.Sha, todo.Pick, getCommentChar())
return utils.MoveTodosUp(path, todosToMove, false, getCommentChar())
})
}
type MoveTodoDownInstruction struct {
Sha string
type MoveTodosDownInstruction struct {
Hashes []string
}
func NewMoveTodoDownInstruction(sha string) Instruction {
return &MoveTodoDownInstruction{
Sha: sha,
func NewMoveTodosDownInstruction(hashes []string) Instruction {
return &MoveTodosDownInstruction{
Hashes: hashes,
}
}
func (self *MoveTodoDownInstruction) Kind() DaemonKind {
return DaemonKindMoveTodoDown
func (self *MoveTodosDownInstruction) Kind() DaemonKind {
return DaemonKindMoveTodosDown
}
func (self *MoveTodoDownInstruction) SerializedInstructions() string {
func (self *MoveTodosDownInstruction) SerializedInstructions() string {
return serializeInstruction(self)
}
func (self *MoveTodoDownInstruction) run(common *common.Common) error {
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
return utils.Todo{
Hash: hash,
}
})
return handleInteractiveRebase(common, func(path string) error {
return utils.MoveTodoDown(path, self.Sha, todo.Pick, getCommentChar())
return utils.MoveTodosDown(path, todosToMove, false, getCommentChar())
})
}
@@ -314,3 +378,27 @@ func (self *InsertBreakInstruction) run(common *common.Common) error {
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)
})
}

View File

@@ -5,11 +5,12 @@ import (
"path/filepath"
"strings"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/env"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
type TodoLine struct {
@@ -21,20 +22,20 @@ func (self *TodoLine) ToString() string {
if self.Action == "break" {
return self.Action + "\n"
} else {
return self.Action + " " + self.Commit.Sha + " " + self.Commit.Name + "\n"
return self.Action + " " + self.Commit.Hash + " " + self.Commit.Name + "\n"
}
}
func TodoLinesToString(todoLines []TodoLine) string {
lines := slices.Map(todoLines, func(todoLine TodoLine) string {
lines := lo.Map(todoLines, func(todoLine TodoLine, _ int) string {
return todoLine.ToString()
})
return strings.Join(slices.Reverse(lines), "")
return strings.Join(lo.Reverse(lines), "")
}
type ChangeTodoAction struct {
Sha string
Hash string
NewAction todo.TodoCommand
}
@@ -44,6 +45,10 @@ func handleInteractiveRebase(common *common.Common, f func(path string) error) e
path := os.Args[1]
if strings.HasSuffix(path, "git-rebase-todo") {
err := utils.RemoveUpdateRefsForCopiedBranch(path, getCommentChar())
if err != nil {
return err
}
return f(path)
} else if strings.HasSuffix(path, filepath.Join(gitDir(), "COMMIT_EDITMSG")) { // TODO: test
// if we are rebasing and squashing, we'll see a COMMIT_EDITMSG

View File

@@ -4,7 +4,10 @@ import (
"bytes"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/exec"
"path/filepath"
"runtime"
"runtime/debug"
@@ -17,7 +20,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/env"
integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types"
"github.com/jesseduffield/lazygit/pkg/logs/tail"
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"gopkg.in/yaml.v3"
@@ -27,15 +29,17 @@ type cliArgs struct {
RepoPath string
FilterPath string
GitArg string
PrintVersionInfo bool
Debug bool
TailLogs bool
PrintDefaultConfig bool
PrintConfigDir bool
UseConfigDir string
WorkTree string
GitDir string
CustomConfigFile string
ScreenMode string
PrintVersionInfo bool
Debug bool
TailLogs bool
Profile bool
PrintDefaultConfig bool
PrintConfigDir bool
}
type BuildInfo struct {
@@ -63,8 +67,17 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
log.Fatal(absRepoPath + " is not a valid git repository.")
}
cliArgs.WorkTree = absRepoPath
cliArgs.GitDir = filepath.Join(absRepoPath, ".git")
err = os.Chdir(absRepoPath)
if err != nil {
log.Fatalf("Failed to change directory to %s: %v", absRepoPath, err)
}
} else if cliArgs.WorkTree != "" {
env.SetWorkTreeEnv(cliArgs.WorkTree)
if err := os.Chdir(cliArgs.WorkTree); err != nil {
log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err)
}
}
if cliArgs.CustomConfigFile != "" {
@@ -75,10 +88,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir)
}
if cliArgs.WorkTree != "" {
env.SetGitWorkTreeEnv(cliArgs.WorkTree)
}
if cliArgs.GitDir != "" {
env.SetGitDirEnv(cliArgs.GitDir)
}
@@ -115,12 +124,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
os.Exit(0)
}
if cliArgs.WorkTree != "" {
if err := os.Chdir(cliArgs.WorkTree); err != nil {
log.Fatal(err.Error())
}
}
tempDir, err := os.MkdirTemp("", "lazygit-*")
if err != nil {
log.Fatal(err.Error())
@@ -134,6 +137,12 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
if integrationTest != nil {
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)
@@ -146,9 +155,17 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes
return
}
if cliArgs.Profile {
go func() {
if err := http.ListenAndServe("localhost:6060", nil); err != nil {
log.Fatal(err)
}
}()
}
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 {
@@ -172,6 +189,9 @@ func parseCliArgsAndEnvVars() *cliArgs {
tailLogs := false
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
flaggy.Bool(&printDefaultConfig, "c", "config", "Print the default config")
@@ -181,15 +201,18 @@ func parseCliArgsAndEnvVars() *cliArgs {
useConfigDir := ""
flaggy.String(&useConfigDir, "ucd", "use-config-dir", "override default config directory with provided directory")
workTree := ""
workTree := os.Getenv("GIT_WORK_TREE")
flaggy.String(&workTree, "w", "work-tree", "equivalent of the --work-tree git argument")
gitDir := ""
gitDir := os.Getenv("GIT_DIR")
flaggy.String(&gitDir, "g", "git-dir", "equivalent of the --git-dir git argument")
customConfigFile := ""
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()
if os.Getenv("DEBUG") == "TRUE" {
@@ -203,12 +226,14 @@ func parseCliArgsAndEnvVars() *cliArgs {
PrintVersionInfo: printVersionInfo,
Debug: debug,
TailLogs: tailLogs,
Profile: profile,
PrintDefaultConfig: printDefaultConfig,
PrintConfigDir: printConfigDir,
UseConfigDir: useConfigDir,
WorkTree: workTree,
GitDir: gitDir,
CustomConfigFile: customConfigFile,
ScreenMode: screenMode,
}
}
@@ -264,7 +289,7 @@ func mergeBuildInfo(buildInfo *BuildInfo) {
buildInfo.Commit = revision.Value
// if lazygit was built from source we'll show the version as the
// 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
@@ -277,7 +302,7 @@ func mergeBuildInfo(buildInfo *BuildInfo) {
}
func getGitVersionInfo() string {
cmd := secureexec.Command("git", "--version")
cmd := exec.Command("git", "--version")
stdout, _ := cmd.Output()
gitVersion := strings.Trim(strings.TrimPrefix(string(stdout), "git version "), " \r\n")
return gitVersion

View File

@@ -3,8 +3,8 @@ package app
import (
"strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/samber/lo"
)
type errorMapping struct {
@@ -18,7 +18,7 @@ func knownError(tr *i18n.TranslationSet, err error) (string, bool) {
knownErrorMessages := []string{tr.MinGitVersionError}
if slices.Contains(knownErrorMessages, errorMessage) {
if lo.Contains(knownErrorMessages, errorMessage) {
return errorMessage, true
}
@@ -27,9 +27,13 @@ func knownError(tr *i18n.TranslationSet, err error) (string, bool) {
originalError: "fatal: not a git repository",
newError: tr.NotARepository,
},
{
originalError: "getwd: no such file or directory",
newError: tr.WorkingDirectoryDoesNotExist,
},
}
if mapping, ok := slices.Find(mappings, func(mapping errorMapping) bool {
if mapping, ok := lo.Find(mappings, func(mapping errorMapping) bool {
return strings.Contains(errorMessage, mapping.originalError)
}); ok {
return mapping.newError, true

View File

@@ -6,12 +6,14 @@ import (
// StartArgs is the struct that represents some things we want to do on program start
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 GitArg
// integration test (only relevant when invoking lazygit in the context of an integration test)
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
@@ -24,10 +26,11 @@ const (
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{
FilterPath: filterPath,
GitArg: gitArg,
ScreenMode: screenMode,
IntegrationTest: test,
}
}

View File

@@ -1,77 +0,0 @@
package cheatsheet
import (
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"regexp"
"github.com/pmezard/go-difflib/difflib"
)
func Check() {
dir := GetKeybindingsDir()
tmpDir := filepath.Join(os.TempDir(), "lazygit_cheatsheet")
err := os.RemoveAll(tmpDir)
if err != nil {
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
}
err = os.Mkdir(tmpDir, 0o700)
if err != nil {
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
}
generateAtDir(tmpDir)
defer os.RemoveAll(tmpDir)
actualContent := obtainContent(dir)
expectedContent := obtainContent(tmpDir)
if expectedContent == "" {
log.Fatal("empty expected content")
}
if actualContent != expectedContent {
err := difflib.WriteUnifiedDiff(os.Stdout, difflib.UnifiedDiff{
A: difflib.SplitLines(expectedContent),
B: difflib.SplitLines(actualContent),
FromFile: "Expected",
FromDate: "",
ToFile: "Actual",
ToDate: "",
Context: 1,
})
if err != nil {
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
}
fmt.Printf("\nCheatsheets are out of date. Please run `%s` at the project root and commit the changes. If you run the script and no keybindings files are updated as a result, try rebasing onto master and trying again.\n", CommandToRun())
os.Exit(1)
}
fmt.Println("\nCheatsheets are up to date")
}
func obtainContent(dir string) string {
re := regexp.MustCompile(`Keybindings_\w+\.md$`)
content := ""
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if re.MatchString(path) {
bytes, err := os.ReadFile(path)
if err != nil {
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
}
content += fmt.Sprintf("\n%s\n\n", filepath.Base(path))
content += string(bytes)
}
return nil
})
if err != nil {
log.Fatalf("Error occurred while checking if cheatsheets are up to date: %v", err)
}
return content
}

View File

@@ -1,10 +1,12 @@
// This "script" generates a file called Keybindings_{{.LANG}}.md
// in current working directory.
//go:generate go run generator.go
// This "script" generates files called Keybindings_{{.LANG}}.md
// in the docs/keybindings directory.
//
// The content of this generated file is a keybindings cheatsheet.
// The content of these generated files is a keybindings cheatsheet.
//
// To generate cheatsheet in english run:
// go run scripts/generate_cheatsheet.go
// To generate the cheatsheets, run:
// go generate pkg/cheatsheet/generate.go
package cheatsheet
@@ -12,10 +14,8 @@ import (
"fmt"
"log"
"os"
"strings"
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazycore/pkg/utils"
"github.com/jesseduffield/lazygit/pkg/app"
"github.com/jesseduffield/lazygit/pkg/config"
@@ -23,6 +23,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/samber/lo"
"golang.org/x/exp/slices"
)
type bindingSection struct {
@@ -42,7 +43,7 @@ type headerWithBindings struct {
}
func CommandToRun() string {
return "go run scripts/cheatsheet/main.go generate"
return "go generate ./..."
}
func GetKeybindingsDir() string {
@@ -50,7 +51,10 @@ func GetKeybindingsDir() string {
}
func generateAtDir(cheatsheetDir string) {
translationSetsByLang := i18n.GetTranslationSets()
translationSetsByLang, err := i18n.GetTranslationSets()
if err != nil {
log.Fatal(err)
}
mConfig := config.NewDummyAppConfig()
for lang := range translationSetsByLang {
@@ -59,7 +63,12 @@ func generateAtDir(cheatsheetDir string) {
if err != nil {
log.Fatal(err)
}
mApp, _ := app.NewApp(mConfig, common)
tr, err := i18n.NewTranslationSetFromConfig(common.Log, lang)
if err != nil {
log.Fatal(err)
}
common.Tr = tr
mApp, _ := app.NewApp(mConfig, nil, common)
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
file, err := os.Create(path)
if err != nil {
@@ -101,7 +110,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
"reflogCommits": tr.ReflogCommitsTitle,
"tags": tr.TagsTitle,
"commitFiles": tr.CommitFilesTitle,
"commitMessage": tr.CommitMessageTitle,
"commitMessage": tr.CommitSummaryTitle,
"commitDescription": tr.CommitDescriptionTitle,
"commits": tr.CommitsTitle,
"confirmation": tr.ConfirmationTitle,
@@ -116,6 +125,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
"stash": tr.StashTitle,
"suggestions": tr.SuggestionsCheatsheetTitle,
"extras": tr.ExtrasTitle,
"worktrees": tr.WorktreesTitle,
}
title, ok := contextTitleMap[str]
@@ -128,7 +138,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*bindingSection {
excludedViews := []string{"stagingSecondary", "patchBuildingSecondary"}
bindingsToDisplay := slices.Filter(bindings, func(binding *types.Binding) bool {
bindingsToDisplay := lo.Filter(bindings, func(binding *types.Binding, _ int) bool {
if lo.Contains(excludedViews, binding.ViewName) {
return false
}
@@ -161,7 +171,7 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b
return a.header.title < b.header.title
})
return slices.Map(bindingGroups, func(hb headerWithBindings) *bindingSection {
return lo.Map(bindingGroups, func(hb headerWithBindings, _ int) *bindingSection {
return &bindingSection{
title: hb.header.title,
bindings: hb.bindings,
@@ -188,11 +198,11 @@ func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection)
for _, section := range bindingSections {
content += formatTitle(section.title)
content += "<pre>\n"
content += "| Key | Action | Info |\n"
content += "|-----|--------|-------------|\n"
for _, binding := range section.bindings {
content += formatBinding(binding)
}
content += "</pre>\n"
}
return content
@@ -203,19 +213,15 @@ func formatTitle(title string) string {
}
func formatBinding(binding *types.Binding) string {
result := fmt.Sprintf(" <kbd>%s</kbd>: %s", escapeAngleBrackets(keybindings.LabelFromKey(binding.Key)), binding.Description)
action := keybindings.LabelFromKey(binding.Key)
description := binding.Description
if binding.Alternative != "" {
result += fmt.Sprintf(" (%s)", binding.Alternative)
action += fmt.Sprintf(" (%s)", binding.Alternative)
}
result += "\n"
return result
}
func escapeAngleBrackets(str string) string {
result := strings.ReplaceAll(str, ">", "&gt;")
result = strings.ReplaceAll(result, "<", "&lt;")
return result
// Use backticks for keyboard keys. Two backticks are needed with an inner space
// to escape a key that is itself a backtick.
return fmt.Sprintf("| `` %s `` | %s | %s |\n", action, description, binding.Tooltip)
}
func italicize(str string) string {

View File

@@ -262,7 +262,7 @@ func TestGetBindingSections(t *testing.T) {
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
actual := getBindingSections(test.bindings, &tr)
actual := getBindingSections(test.bindings, tr)
assert.EqualValues(t, test.expected, actual)
})
}

View File

@@ -0,0 +1,14 @@
//go:build ignore
package main
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/cheatsheet"
)
func main() {
fmt.Printf("Generating cheatsheets in %s...\n", cheatsheet.GetKeybindingsDir())
cheatsheet.Generate()
}

View File

@@ -2,11 +2,9 @@ package commands
import (
"os"
"path/filepath"
"strings"
"github.com/go-errors/errors"
"github.com/sasha-s/go-deadlock"
gogit "github.com/jesseduffield/go-git/v5"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
@@ -14,12 +12,12 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/env"
"github.com/jesseduffield/lazygit/pkg/utils"
)
// GitCommand is our main git interface
type GitCommand struct {
Blame *git_commands.BlameCommands
Branch *git_commands.BranchCommands
Commit *git_commands.CommitCommands
Config *git_commands.ConfigCommands
@@ -37,6 +35,9 @@ type GitCommand struct {
Tag *git_commands.TagCommands
WorkingTree *git_commands.WorkingTreeCommands
Bisect *git_commands.BisectCommands
Worktree *git_commands.WorktreeCommands
Version *git_commands.GitVersion
RepoPaths *git_commands.RepoPaths
Loaders Loaders
}
@@ -50,6 +51,7 @@ type Loaders struct {
RemoteLoader *git_commands.RemoteLoader
StashLoader *git_commands.StashLoader
TagLoader *git_commands.TagLoader
Worktrees *git_commands.WorktreeLoader
}
func NewGitCommand(
@@ -57,19 +59,25 @@ func NewGitCommand(
version *git_commands.GitVersion,
osCommand *oscommands.OSCommand,
gitConfig git_config.IGitConfig,
syncMutex *deadlock.Mutex,
) (*GitCommand, error) {
if err := navigateToRepoRootDirectory(os.Stat, os.Chdir); err != nil {
return nil, err
repoPaths, err := git_commands.GetRepoPaths(osCommand.Cmd, version)
if err != nil {
return nil, errors.Errorf("Error getting repo paths: %v", err)
}
repo, err := setupRepository(gogit.PlainOpenWithOptions, gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true}, cmn.Tr.GitconfigParseErr)
err = os.Chdir(repoPaths.WorktreePath())
if err != nil {
return nil, err
return nil, utils.WrapError(err)
}
dotGitDir, err := findDotGitDir(os.Stat, os.ReadFile)
repository, err := gogit.PlainOpenWithOptions(
repoPaths.WorktreeGitDirPath(),
&gogit.PlainOpenOptions{DetectDotGit: false, EnableDotGitCommonDir: true},
)
if err != nil {
if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) {
return nil, errors.New(cmn.Tr.GitconfigParseErr)
}
return nil, err
}
@@ -78,9 +86,8 @@ func NewGitCommand(
version,
osCommand,
gitConfig,
dotGitDir,
repo,
syncMutex,
repoPaths,
repository,
), nil
}
@@ -89,9 +96,8 @@ func NewGitCommandAux(
version *git_commands.GitVersion,
osCommand *oscommands.OSCommand,
gitConfig git_config.IGitConfig,
dotGitDir string,
repoPaths *git_commands.RepoPaths,
repo *gogit.Repository,
syncMutex *deadlock.Mutex,
) *GitCommand {
cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd)
@@ -102,9 +108,9 @@ func NewGitCommandAux(
// common ones are: cmn, osCommand, dotGitDir, configCommands
configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo)
fileLoader := git_commands.NewFileLoader(cmn, cmd, configCommands)
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, repoPaths, repo, configCommands)
gitCommon := git_commands.NewGitCommon(cmn, version, cmd, osCommand, dotGitDir, repo, configCommands, syncMutex)
fileLoader := git_commands.NewFileLoader(gitCommon, cmd, configCommands)
statusCommands := git_commands.NewStatusCommands(gitCommon)
flowCommands := git_commands.NewFlowCommands(gitCommon)
remoteCommands := git_commands.NewRemoteCommands(gitCommon)
@@ -121,22 +127,24 @@ func NewGitCommandAux(
stashCommands := git_commands.NewStashCommands(gitCommon, fileLoader, workingTreeCommands)
patchBuilder := patch.NewPatchBuilder(cmn.Log,
func(from string, to string, reverse bool, filename string, plain bool) (string, error) {
// TODO: make patch builder take Gui.IgnoreWhitespaceInDiffView into
// account. For now we just pass false.
return workingTreeCommands.ShowFileDiff(from, to, reverse, filename, plain, false)
return workingTreeCommands.ShowFileDiff(from, to, reverse, filename, plain)
})
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
bisectCommands := git_commands.NewBisectCommands(gitCommon)
worktreeCommands := git_commands.NewWorktreeCommands(gitCommon)
blameCommands := git_commands.NewBlameCommands(gitCommon)
branchLoader := git_commands.NewBranchLoader(cmn, cmd, branchCommands.CurrentBranchInfo, configCommands)
branchLoader := git_commands.NewBranchLoader(cmn, gitCommon, cmd, branchCommands.CurrentBranchInfo, configCommands)
commitFileLoader := git_commands.NewCommitFileLoader(cmn, cmd)
commitLoader := git_commands.NewCommitLoader(cmn, cmd, dotGitDir, statusCommands.RebaseMode, gitCommon)
commitLoader := git_commands.NewCommitLoader(cmn, cmd, statusCommands.RebaseMode, gitCommon)
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
worktreeLoader := git_commands.NewWorktreeLoader(gitCommon)
stashLoader := git_commands.NewStashLoader(cmn, cmd)
tagLoader := git_commands.NewTagLoader(cmn, cmd)
return &GitCommand{
Blame: blameCommands,
Branch: branchCommands,
Commit: commitCommands,
Config: configCommands,
@@ -154,6 +162,8 @@ func NewGitCommandAux(
Tag: tagCommands,
Bisect: bisectCommands,
WorkingTree: workingTreeCommands,
Worktree: worktreeCommands,
Version: version,
Loaders: Loaders{
BranchLoader: branchLoader,
CommitFileLoader: commitFileLoader,
@@ -161,121 +171,14 @@ func NewGitCommandAux(
FileLoader: fileLoader,
ReflogCommitLoader: reflogCommitLoader,
RemoteLoader: remoteLoader,
Worktrees: worktreeLoader,
StashLoader: stashLoader,
TagLoader: tagLoader,
},
RepoPaths: repoPaths,
}
}
func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir func(string) error) error {
gitDir := env.GetGitDirEnv()
if gitDir != "" {
// we've been given the git directory explicitly so no need to navigate to it
_, err := stat(gitDir)
if err != nil {
return utils.WrapError(err)
}
return nil
}
// we haven't been given the git dir explicitly so we assume it's in the current working directory as `.git/` (or an ancestor directory)
for {
_, err := stat(".git")
if err == nil {
return nil
}
if !os.IsNotExist(err) {
return utils.WrapError(err)
}
if err = chdir(".."); err != nil {
return utils.WrapError(err)
}
currentPath, err := os.Getwd()
if err != nil {
return err
}
atRoot := currentPath == filepath.Dir(currentPath)
if atRoot {
// we should never really land here: the code that creates GitCommand should
// verify we're in a git directory
return errors.New("Must open lazygit in a git repository")
}
}
}
// resolvePath takes a path containing a symlink and returns the true path
func resolvePath(path string) (string, error) {
l, err := os.Lstat(path)
if err != nil {
return "", err
}
if l.Mode()&os.ModeSymlink == 0 {
return path, nil
}
return filepath.EvalSymlinks(path)
}
func setupRepository(openGitRepository func(string, *gogit.PlainOpenOptions) (*gogit.Repository, error), options gogit.PlainOpenOptions, gitConfigParseErrorStr string) (*gogit.Repository, error) {
unresolvedPath := env.GetGitDirEnv()
if unresolvedPath == "" {
var err error
unresolvedPath, err = os.Getwd()
if err != nil {
return nil, err
}
}
path, err := resolvePath(unresolvedPath)
if err != nil {
return nil, err
}
repository, err := openGitRepository(path, &options)
if err != nil {
if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) {
return nil, errors.New(gitConfigParseErrorStr)
}
return nil, err
}
return repository, err
}
func findDotGitDir(stat func(string) (os.FileInfo, error), readFile func(filename string) ([]byte, error)) (string, error) {
if env.GetGitDirEnv() != "" {
return env.GetGitDirEnv(), nil
}
f, err := stat(".git")
if err != nil {
return "", err
}
if f.IsDir() {
return ".git", nil
}
fileBytes, err := readFile(".git")
if err != nil {
return "", err
}
fileContent := string(fileBytes)
if !strings.HasPrefix(fileContent, "gitdir: ") {
return "", errors.New(".git is a file which suggests we are in a submodule or a worktree but the file's contents do not contain a gitdir pointing to the actual .git directory")
}
return strings.TrimSpace(strings.TrimPrefix(fileContent, "gitdir: ")), nil
}
func VerifyInGitRepo(osCommand *oscommands.OSCommand) error {
return osCommand.Cmd.New(git_commands.NewGitCmd("rev-parse").Arg("--git-dir").ToArgv()).DontLog().Run()
}

View File

@@ -38,6 +38,10 @@ func (self *gitCmdObjBuilder) NewShell(cmdStr string) oscommands.ICmdObj {
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 {
return self.innerBuilder.Quote(str)
}

View File

@@ -19,12 +19,16 @@ func NewBisectCommands(gitCommon *GitCommon) *BisectCommands {
// This command is pretty cheap to run so we're not storing the result anywhere.
// But if it becomes problematic we can chang that.
func (self *BisectCommands) GetInfo() *BisectInfo {
return self.GetInfoForGitDir(self.repoPaths.WorktreeGitDirPath())
}
func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
var err error
info := &BisectInfo{started: false, log: self.Log, newTerm: "bad", oldTerm: "good"}
// we return nil if we're not in a git bisect session.
// we know we're in a session by the presence of a .git/BISECT_START file
bisectStartPath := filepath.Join(self.dotGitDir, "BISECT_START")
bisectStartPath := filepath.Join(gitDir, "BISECT_START")
exists, err := self.os.FileExists(bisectStartPath)
if err != nil {
self.Log.Infof("error getting git bisect info: %s", err.Error())
@@ -44,7 +48,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
info.started = true
info.start = strings.TrimSpace(string(startContent))
termsContent, err := os.ReadFile(filepath.Join(self.dotGitDir, "BISECT_TERMS"))
termsContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_TERMS"))
if err != nil {
// old git versions won't have this file so we default to bad/good
} else {
@@ -53,7 +57,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
info.oldTerm = splitContent[1]
}
bisectRefsDir := filepath.Join(self.dotGitDir, "refs", "bisect")
bisectRefsDir := filepath.Join(gitDir, "refs", "bisect")
files, err := os.ReadDir(bisectRefsDir)
if err != nil {
self.Log.Infof("error getting git bisect info: %s", err.Error())
@@ -72,7 +76,7 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
return info
}
sha := strings.TrimSpace(string(fileContent))
hash := strings.TrimSpace(string(fileContent))
if name == info.newTerm {
status = BisectStatusNew
@@ -82,16 +86,16 @@ func (self *BisectCommands) GetInfo() *BisectInfo {
status = BisectStatusSkipped
}
info.statusMap[sha] = status
info.statusMap[hash] = status
}
currentContent, err := os.ReadFile(filepath.Join(self.dotGitDir, "BISECT_EXPECTED_REV"))
currentContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_EXPECTED_REV"))
if err != nil {
self.Log.Infof("error getting git bisect info: %s", err.Error())
return info
}
currentSha := strings.TrimSpace(string(currentContent))
info.current = currentSha
currentHash := strings.TrimSpace(string(currentContent))
info.current = currentHash
return info
}
@@ -121,8 +125,17 @@ func (self *BisectCommands) Start() error {
return self.cmd.New(cmdArgs).StreamOutput().Run()
}
func (self *BisectCommands) StartWithTerms(oldTerm string, newTerm string) error {
cmdArgs := NewGitCmd("bisect").Arg("start").
Arg("--term-old=" + oldTerm).
Arg("--term-new=" + newTerm).
ToArgv()
return self.cmd.New(cmdArgs).StreamOutput().Run()
}
// tells us whether we've found our problem commit(s). We return a string slice of
// 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.
func (self *BisectCommands) IsDone() (bool, []string, error) {
info := self.GetInfo()
@@ -130,8 +143,8 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
return false, nil, nil
}
newSha := info.GetNewSha()
if newSha == "" {
newHash := info.GetNewHash()
if newHash == "" {
return false, nil, nil
}
@@ -140,14 +153,14 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
done := false
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) {
sha := strings.TrimSpace(line)
hash := strings.TrimSpace(line)
if status, ok := info.statusMap[sha]; ok {
if status, ok := info.statusMap[hash]; ok {
switch status {
case BisectStatusSkipped, BisectStatusNew:
candidates = append(candidates, sha)
candidates = append(candidates, hash)
return false, nil
case BisectStatusOld:
done = true
@@ -172,7 +185,7 @@ func (self *BisectCommands) IsDone() (bool, []string, error) {
// render the commits from the bad commit.
func (self *BisectCommands) ReachableFromStart(bisectInfo *BisectInfo) bool {
cmdArgs := NewGitCmd("merge-base").
Arg("--is-ancestor", bisectInfo.GetNewSha(), bisectInfo.GetStartSha()).
Arg("--is-ancestor", bisectInfo.GetNewHash(), bisectInfo.GetStartHash()).
ToArgv()
err := self.cmd.New(cmdArgs).DontLog().Run()

View File

@@ -2,7 +2,7 @@ package git_commands
import (
"github.com/jesseduffield/generics/maps"
"github.com/jesseduffield/generics/slices"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
)
@@ -29,10 +29,10 @@ type BisectInfo struct {
newTerm string // 'bad' 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
// the sha of the commit that's under test
// the hash of the commit that's under test
current string
}
@@ -49,26 +49,26 @@ func NewNullBisectInfo() *BisectInfo {
return &BisectInfo{started: false}
}
func (self *BisectInfo) GetNewSha() string {
for sha, status := range self.statusMap {
func (self *BisectInfo) GetNewHash() string {
for hash, status := range self.statusMap {
if status == BisectStatusNew {
return sha
return hash
}
}
return ""
}
func (self *BisectInfo) GetCurrentSha() string {
func (self *BisectInfo) GetCurrentHash() string {
return self.current
}
func (self *BisectInfo) GetStartSha() string {
func (self *BisectInfo) GetStartHash() string {
return self.start
}
func (self *BisectInfo) Status(commitSha string) (BisectStatus, bool) {
status, ok := self.statusMap[commitSha]
func (self *BisectInfo) Status(commitHash string) (BisectStatus, bool) {
status, ok := self.statusMap[commitHash]
return status, ok
}
@@ -93,9 +93,9 @@ func (self *BisectInfo) Bisecting() bool {
return false
}
if self.GetNewSha() == "" {
if self.GetNewHash() == "" {
return false
}
return slices.Contains(maps.Values(self.statusMap), BisectStatusOld)
return lo.Contains(maps.Values(self.statusMap), BisectStatusOld)
}

View File

@@ -0,0 +1,33 @@
package git_commands
import (
"fmt"
)
type BlameCommands struct {
*GitCommon
}
func NewBlameCommands(gitCommon *GitCommon) *BlameCommands {
return &BlameCommands{
GitCommon: gitCommon,
}
}
// Blame a range of lines. For each line, output the hash of the commit where
// the line last changed, then a space, then a description of the commit (author
// and date), another space, and then the line. For example:
//
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 11) func NewBlameCommands(gitCommon *GitCommon) *BlameCommands {
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 12) return &BlameCommands{
// ac90ebac688fe8bc2ffd922157a9d2c54681d2aa (Stefan Haller 2023-08-01 14:54:56 +0200 13) GitCommon: gitCommon,
func (self *BlameCommands) BlameLineRange(filename string, commit string, firstLine int, numLines int) (string, error) {
cmdArgs := NewGitCmd("blame").
Arg("-l").
Arg(fmt.Sprintf("-L%d,+%d", firstLine, numLines)).
Arg(commit).
Arg("--").
Arg(filename)
return self.cmd.New(cmdArgs.ToArgv()).RunWithOutput()
}

View File

@@ -4,13 +4,16 @@ import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mgutz/str"
"github.com/samber/lo"
)
type BranchCommands struct {
*GitCommon
allBranchesLogCmdIndex uint8 // keeps track of current all branches log command
}
func NewBranchCommands(gitCommon *GitCommon) *BranchCommands {
@@ -28,6 +31,26 @@ func (self *BranchCommands) New(name string, base string) error {
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.
func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
branchName, err := self.cmd.New(
@@ -54,10 +77,10 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
for _, line := range utils.SplitLines(output) {
split := strings.Split(strings.TrimRight(line, "\r\n"), "\x00")
if len(split) == 3 && split[0] == "*" {
sha := split[1]
hash := split[1]
displayName := split[2]
return BranchInfo{
RefName: sha,
RefName: hash,
DisplayName: displayName,
DetachedHead: true,
}, nil
@@ -70,11 +93,26 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
}, nil
}
// Delete delete branch
func (self *BranchCommands) Delete(branch string, force bool) error {
// CurrentBranchName get name of current branch
func (self *BranchCommands) CurrentBranchName() (string, error) {
cmdArgs := NewGitCmd("rev-parse").
Arg("--abbrev-ref").
Arg("--verify").
Arg("HEAD").
ToArgv()
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err == nil {
return strings.TrimSpace(output), nil
}
return "", err
}
// LocalDelete delete branch locally
func (self *BranchCommands) LocalDelete(branches []string, force bool) error {
cmdArgs := NewGitCmd("branch").
ArgIfElse(force, "-D", "-d").
Arg(branch).
Arg(branches...).
ToArgv()
return self.cmd.New(cmdArgs).Run()
@@ -108,7 +146,7 @@ func (self *BranchCommands) GetGraph(branchName string) (string, error) {
}
func (self *BranchCommands) GetGraphCmdObj(branchName string) oscommands.ICmdObj {
branchLogCmdTemplate := self.UserConfig.Git.BranchLogCmd
branchLogCmdTemplate := self.UserConfig().Git.BranchLogCmd
templateValues := map[string]string{
"branchName": self.cmd.Quote(branchName),
}
@@ -190,13 +228,18 @@ func (self *BranchCommands) Rename(oldName string, newName string) error {
type MergeOpts struct {
FastForwardOnly bool
Squash bool
}
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").
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.Squash, "--squash", "--ff").
Arg(branchName).
ToArgv()
@@ -204,5 +247,41 @@ func (self *BranchCommands) Merge(branchName string, opts MergeOpts) error {
}
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
}

View File

@@ -3,16 +3,19 @@ package git_commands
import (
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/jesseduffield/generics/set"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/go-git/v5/config"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"golang.org/x/exp/slices"
"golang.org/x/sync/errgroup"
)
// context:
@@ -39,6 +42,7 @@ type BranchInfo struct {
// BranchLoader returns a list of Branch objects for the current repo
type BranchLoader struct {
*common.Common
*GitCommon
cmd oscommands.ICmdObjBuilder
getCurrentBranchInfo func() (BranchInfo, error)
config BranchLoaderConfigCommands
@@ -46,12 +50,14 @@ type BranchLoader struct {
func NewBranchLoader(
cmn *common.Common,
gitCommon *GitCommon,
cmd oscommands.ICmdObjBuilder,
getCurrentBranchInfo func() (BranchInfo, error),
config BranchLoaderConfigCommands,
) *BranchLoader {
return &BranchLoader{
Common: cmn,
GitCommon: gitCommon,
cmd: cmd,
getCurrentBranchInfo: getCurrentBranchInfo,
config: config,
@@ -59,36 +65,49 @@ func NewBranchLoader(
}
// Load the list of branches for the current repo
func (self *BranchLoader) Load(reflogCommits []*models.Commit) ([]*models.Branch, error) {
branches := self.obtainBranches()
func (self *BranchLoader) Load(reflogCommits []*models.Commit,
mainBranches *MainBranches,
oldBranches []*models.Branch,
loadBehindCounts bool,
onWorker func(func() error),
renderFunc func(),
) ([]*models.Branch, error) {
branches := self.obtainBranches(self.version.IsAtLeast(2, 22, 0))
reflogBranches := self.obtainReflogBranches(reflogCommits)
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*models.Branch, 0)
outer:
for _, reflogBranch := range reflogBranches {
for j, branch := range branches {
if branch.Head {
continue
}
if strings.EqualFold(reflogBranch.Name, branch.Name) {
branch.Recency = reflogBranch.Recency
branchesWithRecency = append(branchesWithRecency, branch)
branches = slices.Remove(branches, j)
continue outer
if self.AppState.LocalBranchSortOrder == "recency" {
reflogBranches := self.obtainReflogBranches(reflogCommits)
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*models.Branch, 0)
outer:
for _, reflogBranch := range reflogBranches {
for j, branch := range branches {
if branch.Head {
continue
}
if strings.EqualFold(reflogBranch.Name, branch.Name) {
branch.Recency = reflogBranch.Recency
branchesWithRecency = append(branchesWithRecency, branch)
branches = utils.Remove(branches, j)
continue outer
}
}
}
}
branches = slices.Prepend(branches, branchesWithRecency...)
// Sort branches that don't have a recency value alphabetically
// (we're really doing this for the sake of deterministic behaviour across git versions)
slices.SortFunc(branches, func(a *models.Branch, b *models.Branch) bool {
return a.Name < b.Name
})
branches = utils.Prepend(branches, branchesWithRecency...)
}
foundHead := false
for i, branch := range branches {
if branch.Head {
foundHead = true
branch.Recency = " *"
branches = slices.Move(branches, i, 0)
branches = utils.Move(branches, i, 0)
break
}
}
@@ -97,7 +116,7 @@ outer:
if err != nil {
return nil, err
}
branches = slices.Prepend(branches, &models.Branch{Name: info.RefName, DisplayName: info.DisplayName, Head: true, DetachedHead: info.DetachedHead, Recency: " *"})
branches = utils.Prepend(branches, &models.Branch{Name: info.RefName, DisplayName: info.DisplayName, Head: true, DetachedHead: info.DetachedHead, Recency: " *"})
}
configBranches, err := self.config.Branches()
@@ -111,12 +130,109 @@ outer:
branch.UpstreamRemote = match.Remote
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
}
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()
if err != nil {
panic(err)
@@ -125,7 +241,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
trimmedOutput := strings.TrimSpace(output)
outputLines := strings.Split(trimmedOutput, "\n")
return slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) {
return lo.FilterMap(outputLines, func(line string, _ int) (*models.Branch, bool) {
if line == "" {
return nil, false
}
@@ -138,7 +254,8 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
return nil, false
}
return obtainBranch(split), true
storeCommitDateAsRecency := self.AppState.LocalBranchSortOrder != "recency"
return obtainBranch(split, storeCommitDateAsRecency, canUsePushTrack), true
})
}
@@ -150,8 +267,18 @@ func (self *BranchLoader) getRawBranches() (string, error) {
"%00",
)
var sortOrder string
switch strings.ToLower(self.AppState.LocalBranchSortOrder) {
case "recency", "date":
sortOrder = "-committerdate"
case "alphabetical":
sortOrder = "refname"
default:
sortOrder = "refname"
}
cmdArgs := NewGitCmd("for-each-ref").
Arg("--sort=-committerdate").
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
Arg(fmt.Sprintf("--format=%s", format)).
Arg("refs/heads").
ToArgv()
@@ -164,30 +291,50 @@ var branchFields = []string{
"refname:short",
"upstream:short",
"upstream:track",
"push:track",
"subject",
fmt.Sprintf("objectname:short=%d", utils.COMMIT_HASH_SHORT_SIZE),
"objectname",
"committerdate:unix",
}
// Obtain branch information from parsed line output of getRawBranches()
func obtainBranch(split []string) *models.Branch {
func obtainBranch(split []string, storeCommitDateAsRecency bool, canUsePushTrack bool) *models.Branch {
headMarker := split[0]
fullName := split[1]
upstreamName := split[2]
track := split[3]
subject := split[4]
commitHash := split[5]
pushTrack := split[4]
subject := split[5]
commitHash := split[6]
commitDate := split[7]
name := strings.TrimPrefix(fullName, "heads/")
pushables, pullables, gone := parseUpstreamInfo(upstreamName, track)
aheadForPull, behindForPull, gone := parseUpstreamInfo(upstreamName, track)
var aheadForPush, behindForPush string
if canUsePushTrack {
aheadForPush, behindForPush, _ = parseUpstreamInfo(upstreamName, pushTrack)
} else {
aheadForPush, behindForPush = aheadForPull, behindForPull
}
recency := ""
if storeCommitDateAsRecency {
if unixTimestamp, err := strconv.ParseInt(commitDate, 10, 64); err == nil {
recency = utils.UnixToTimeAgo(unixTimestamp)
}
}
return &models.Branch{
Name: name,
Pushables: pushables,
Pullables: pullables,
UpstreamGone: gone,
Head: headMarker == "*",
Subject: subject,
CommitHash: commitHash,
Name: name,
Recency: recency,
AheadForPull: aheadForPull,
BehindForPull: behindForPull,
AheadForPush: aheadForPush,
BehindForPush: behindForPush,
UpstreamGone: gone,
Head: headMarker == "*",
Subject: subject,
CommitHash: commitHash,
}
}
@@ -203,10 +350,10 @@ func parseUpstreamInfo(upstreamName string, track string) (string, string, bool)
return "?", "?", true
}
pushables := parseDifference(track, `ahead (\d+)`)
pullables := parseDifference(track, `behind (\d+)`)
ahead := parseDifference(track, `ahead (\d+)`)
behind := parseDifference(track, `behind (\d+)`)
return pushables, pullables, false
return ahead, behind, false
}
func parseDifference(track string, regexStr string) string {

View File

@@ -2,7 +2,9 @@ package git_commands
// "*|feat/detect-purge|origin/feat/detect-purge|[ahead 1]"
import (
"strconv"
"testing"
"time"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/stretchr/testify/assert"
@@ -10,78 +12,114 @@ import (
func TestObtainBranch(t *testing.T) {
type scenario struct {
testName string
input []string
expectedBranch *models.Branch
testName string
input []string
storeCommitDateAsRecency bool
expectedBranch *models.Branch
}
// Use a time stamp of 2 1/2 hours ago, resulting in a recency string of "2h"
now := time.Now().Unix()
timeStamp := strconv.Itoa(int(now - 2.5*60*60))
scenarios := []scenario{
{
testName: "TrimHeads",
input: []string{"", "heads/a_branch", "", "", "subject", "123"},
testName: "TrimHeads",
input: []string{"", "heads/a_branch", "", "", "", "subject", "123", timeStamp},
storeCommitDateAsRecency: false,
expectedBranch: &models.Branch{
Name: "a_branch",
Pushables: "?",
Pullables: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
Name: "a_branch",
AheadForPull: "?",
BehindForPull: "?",
AheadForPush: "?",
BehindForPush: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
},
},
{
testName: "NoUpstream",
input: []string{"", "a_branch", "", "", "subject", "123"},
testName: "NoUpstream",
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
storeCommitDateAsRecency: false,
expectedBranch: &models.Branch{
Name: "a_branch",
Pushables: "?",
Pullables: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
Name: "a_branch",
AheadForPull: "?",
BehindForPull: "?",
AheadForPush: "?",
BehindForPush: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
},
},
{
testName: "IsHead",
input: []string{"*", "a_branch", "", "", "subject", "123"},
testName: "IsHead",
input: []string{"*", "a_branch", "", "", "", "subject", "123", timeStamp},
storeCommitDateAsRecency: false,
expectedBranch: &models.Branch{
Name: "a_branch",
Pushables: "?",
Pullables: "?",
Head: true,
Subject: "subject",
CommitHash: "123",
Name: "a_branch",
AheadForPull: "?",
BehindForPull: "?",
AheadForPush: "?",
BehindForPush: "?",
Head: true,
Subject: "subject",
CommitHash: "123",
},
},
{
testName: "IsBehindAndAhead",
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "subject", "123"},
testName: "IsBehindAndAhead",
input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]", "[behind 2, ahead 3]", "subject", "123", timeStamp},
storeCommitDateAsRecency: false,
expectedBranch: &models.Branch{
Name: "a_branch",
Pushables: "3",
Pullables: "2",
Head: false,
Subject: "subject",
CommitHash: "123",
Name: "a_branch",
AheadForPull: "3",
BehindForPull: "2",
AheadForPush: "3",
BehindForPush: "2",
Head: false,
Subject: "subject",
CommitHash: "123",
},
},
{
testName: "RemoteBranchIsGone",
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "subject", "123"},
testName: "RemoteBranchIsGone",
input: []string{"", "a_branch", "a_remote/a_branch", "[gone]", "[gone]", "subject", "123", timeStamp},
storeCommitDateAsRecency: false,
expectedBranch: &models.Branch{
Name: "a_branch",
UpstreamGone: true,
Pushables: "?",
Pullables: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
Name: "a_branch",
UpstreamGone: true,
AheadForPull: "?",
BehindForPull: "?",
AheadForPush: "?",
BehindForPush: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
},
},
{
testName: "WithCommitDateAsRecency",
input: []string{"", "a_branch", "", "", "", "subject", "123", timeStamp},
storeCommitDateAsRecency: true,
expectedBranch: &models.Branch{
Name: "a_branch",
Recency: "2h",
AheadForPull: "?",
BehindForPull: "?",
AheadForPush: "?",
BehindForPush: "?",
Head: false,
Subject: "subject",
CommitHash: "123",
},
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
branch := obtainBranch(s.input)
branch := obtainBranch(s.input, s.storeCommitDateAsRecency, true)
assert.EqualValues(t, s.expectedBranch, branch)
})
}

View File

@@ -41,7 +41,6 @@ func TestBranchGetCommitDifferences(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildBranchCommands(commonDeps{runner: s.runner})
pushables, pullables := instance.GetCommitDifferences("HEAD", "@{u}")
@@ -63,37 +62,57 @@ func TestBranchNewBranch(t *testing.T) {
func TestBranchDeleteBranch(t *testing.T) {
type scenario struct {
testName string
force bool
runner *oscommands.FakeCmdObjRunner
test func(error)
testName string
branchNames []string
force bool
runner *oscommands.FakeCmdObjRunner
test func(error)
}
scenarios := []scenario{
{
"Delete a branch",
[]string{"test"},
false,
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-d", "test"}, "", nil),
func(err error) {
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",
[]string{"test"},
true,
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"branch", "-D", "test"}, "", nil),
func(err error) {
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 {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildBranchCommands(commonDeps{runner: s.runner})
s.test(instance.Delete("test", s.force))
s.test(instance.LocalDelete(s.branchNames, s.force))
s.runner.CheckForMissingCalls()
})
}
@@ -127,6 +146,19 @@ func TestBranchMerge(t *testing.T) {
branchName: "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",
userConfig: &config.UserConfig{},
@@ -137,7 +169,6 @@ func TestBranchMerge(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
runner := oscommands.NewFakeRunner(t).
ExpectGitArgs(s.expected, "", nil)
@@ -177,7 +208,6 @@ func TestBranchCheckout(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildBranchCommands(commonDeps{runner: s.runner})
s.test(instance.Checkout("test", CheckoutOptions{Force: s.force}))
@@ -266,7 +296,6 @@ func TestBranchCurrentBranchInfo(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildBranchCommands(commonDeps{runner: s.runner})
s.test(instance.CurrentBranchInfo())

View File

@@ -38,9 +38,44 @@ func (self *CommitCommands) SetAuthor(value string) error {
return self.cmd.New(cmdArgs).Run()
}
// Add a commit's coauthor using Github/Gitlab Co-authored-by metadata. Value is expected to be of the form 'Name <Email>'
func (self *CommitCommands) AddCoAuthor(hash string, author string) error {
message, err := self.GetCommitMessage(hash)
if err != nil {
return err
}
message = AddCoAuthorToMessage(message, author)
cmdArgs := NewGitCmd("commit").
Arg("--allow-empty", "--amend", "--only", "-m", message).
ToArgv()
return self.cmd.New(cmdArgs).Run()
}
func AddCoAuthorToMessage(message string, author string) string {
subject, body, _ := strings.Cut(message, "\n")
return strings.TrimSpace(subject) + "\n\n" + AddCoAuthorToDescription(strings.TrimSpace(body), author)
}
func AddCoAuthorToDescription(description string, author string) string {
if description != "" {
lines := strings.Split(description, "\n")
if strings.HasPrefix(lines[len(lines)-1], "Co-authored-by:") {
description += "\n"
} else {
description += "\n\n"
}
}
return description + fmt.Sprintf("Co-authored-by: %s", author)
}
// ResetToCommit reset to commit
func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars []string) error {
cmdArgs := NewGitCmd("reset").Arg("--"+strength, sha).ToArgv()
func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars []string) error {
cmdArgs := NewGitCmd("reset").Arg("--"+strength, hash).ToArgv()
return self.cmd.New(cmdArgs).
// prevents git from prompting us for input which would freeze the program
@@ -50,13 +85,13 @@ func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars [
Run()
}
func (self *CommitCommands) CommitCmdObj(message string) oscommands.ICmdObj {
messageArgs := self.commitMessageArgs(message)
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
messageArgs := self.commitMessageArgs(summary, description)
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
skipHookPrefix := self.UserConfig().Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
Arg(messageArgs...).
ToArgv()
@@ -68,21 +103,33 @@ func (self *CommitCommands) RewordLastCommitInEditorCmdObj() oscommands.ICmdObj
return self.cmd.New(NewGitCmd("commit").Arg("--allow-empty", "--amend", "--only").ToArgv())
}
func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
}
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
Arg("--edit").
Arg("--file="+tmpMessageFile).
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
ToArgv())
}
// RewordLastCommit rewords the topmost commit with the given message
func (self *CommitCommands) RewordLastCommit(message string) error {
messageArgs := self.commitMessageArgs(message)
func (self *CommitCommands) RewordLastCommit(summary string, description string) oscommands.ICmdObj {
messageArgs := self.commitMessageArgs(summary, description)
cmdArgs := NewGitCmd("commit").
Arg("--allow-empty", "--amend", "--only").
Arg(messageArgs...).
ToArgv()
return self.cmd.New(cmdArgs).Run()
return self.cmd.New(cmdArgs)
}
func (self *CommitCommands) commitMessageArgs(message string) []string {
msg, description, _ := strings.Cut(message, "\n")
args := []string{"-m", msg}
func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
args := []string{"-m", summary}
if description != "" {
args = append(args, "-m", description)
@@ -101,33 +148,35 @@ func (self *CommitCommands) CommitEditorCmdObj() oscommands.ICmdObj {
}
func (self *CommitCommands) signoffFlag() string {
if self.UserConfig.Git.Commit.SignOff {
if self.UserConfig().Git.Commit.SignOff {
return "--signoff"
} else {
return ""
}
}
// Get the subject of the HEAD commit
func (self *CommitCommands) GetHeadCommitMessage() (string, error) {
cmdArgs := NewGitCmd("log").Arg("-1", "--pretty=%s").ToArgv()
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return strings.TrimSpace(message), err
}
func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
cmdArgs := NewGitCmd("rev-list").
Arg("--format=%B", "--max-count=1", commitSha).
func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) {
cmdArgs := NewGitCmd("log").
Arg("--format=%B", "--max-count=1", commitHash).
Config("log.showsignature=false").
ToArgv()
messageWithHeader, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
message := strings.Join(strings.SplitAfter(messageWithHeader, "\n")[1:], "")
return strings.TrimSpace(message), err
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
}
func (self *CommitCommands) GetCommitDiff(commitSha string) (string, error) {
cmdArgs := NewGitCmd("show").Arg("--no-color", commitSha).ToArgv()
func (self *CommitCommands) GetCommitSubject(commitHash string) (string, error) {
cmdArgs := NewGitCmd("log").
Arg("--format=%s", "--max-count=1", commitHash).
Config("log.showsignature=false").
ToArgv()
subject, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return strings.TrimSpace(subject), err
}
func (self *CommitCommands) GetCommitDiff(commitHash string) (string, error) {
cmdArgs := NewGitCmd("show").Arg("--no-color", commitHash).ToArgv()
diff, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return diff, err
@@ -138,9 +187,9 @@ type Author struct {
Email string
}
func (self *CommitCommands) GetCommitAuthor(commitSha string) (Author, error) {
func (self *CommitCommands) GetCommitAuthor(commitHash string) (Author, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--pretty=format:'%an%x00%ae'", commitSha).
Arg("--no-patch", "--pretty=format:%an%x00%ae", commitHash).
ToArgv()
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
@@ -157,23 +206,37 @@ func (self *CommitCommands) GetCommitAuthor(commitSha string) (Author, error) {
return author, err
}
func (self *CommitCommands) GetCommitMessageFirstLine(sha string) (string, error) {
return self.GetCommitMessagesFirstLine([]string{sha})
func (self *CommitCommands) GetCommitMessageFirstLine(hash string) (string, error) {
return self.GetCommitMessagesFirstLine([]string{hash})
}
func (self *CommitCommands) GetCommitMessagesFirstLine(shas []string) (string, error) {
func (self *CommitCommands) GetCommitMessagesFirstLine(hashes []string) (string, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--pretty=format:%s").
Arg(shas...).
Arg(hashes...).
ToArgv()
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
}
func (self *CommitCommands) GetCommitsOneline(shas []string) (string, error) {
// Example output:
//
// cd50c79ae Preserve the commit message correctly even if the description has blank lines
// 3ebba5f32 Add test demonstrating a bug with preserving the commit message
// 9a423c388 Remove unused function
func (self *CommitCommands) GetHashesAndCommitMessagesFirstLine(hashes []string) (string, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--pretty=format:%h %s").
Arg(hashes...).
ToArgv()
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
}
func (self *CommitCommands) GetCommitsOneline(hashes []string) (string, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--oneline").
Arg(shas...).
Arg(hashes...).
ToArgv()
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
@@ -192,41 +255,62 @@ func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
return self.cmd.New(cmdArgs)
}
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string, ignoreWhitespace bool) oscommands.ICmdObj {
contextSize := self.UserConfig.Git.DiffContextSize
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
contextSize := self.AppState.DiffContextSize
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
cmdArgs := NewGitCmd("show").
Config("diff.noprefix=false").
ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd).
ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff").
Arg("--submodule").
Arg("--color="+self.UserConfig.Git.Paging.ColorArg).
Arg("--color="+self.UserConfig().Git.Paging.ColorArg).
Arg(fmt.Sprintf("--unified=%d", contextSize)).
Arg("--stat").
Arg("--decorate").
Arg("-p").
Arg(sha).
ArgIf(ignoreWhitespace, "--ignore-all-space").
Arg(hash).
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
ArgIf(filterPath != "", "--", filterPath).
Dir(self.repoPaths.worktreePath).
ToArgv()
return self.cmd.New(cmdArgs).DontLog()
}
// Revert reverts the selected commit by sha
func (self *CommitCommands) Revert(sha string) error {
cmdArgs := NewGitCmd("revert").Arg(sha).ToArgv()
// Revert reverts the selected commit by hash
func (self *CommitCommands) Revert(hash string) error {
cmdArgs := NewGitCmd("revert").Arg(hash).ToArgv()
return self.cmd.New(cmdArgs).Run()
}
func (self *CommitCommands) RevertMerge(sha string, parentNumber int) error {
cmdArgs := NewGitCmd("revert").Arg(sha, "-m", fmt.Sprintf("%d", parentNumber)).
func (self *CommitCommands) RevertMerge(hash string, parentNumber int) error {
cmdArgs := NewGitCmd("revert").Arg(hash, "-m", fmt.Sprintf("%d", parentNumber)).
ToArgv()
return self.cmd.New(cmdArgs).Run()
}
// CreateFixupCommit creates a commit that fixes up a previous commit
func (self *CommitCommands) CreateFixupCommit(sha string) error {
cmdArgs := NewGitCmd("commit").Arg("--fixup=" + sha).ToArgv()
func (self *CommitCommands) CreateFixupCommit(hash string) error {
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()
}

View File

@@ -3,7 +3,6 @@ package git_commands
import (
"strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
@@ -25,6 +24,7 @@ func NewCommitFileLoader(common *common.Common, cmd oscommands.ICmdObjBuilder) *
// GetFilesInDiff get the specified commit files
func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse bool) ([]*models.CommitFile, error) {
cmdArgs := NewGitCmd("diff").
Config("diff.noprefix=false").
Arg("--submodule").
Arg("--no-ext-diff").
Arg("--name-status").
@@ -52,7 +52,7 @@ func getCommitFilesFromFilenames(filenames string) []*models.CommitFile {
}
// typical result looks like 'A my_file' meaning my_file was added
return slices.Map(lo.Chunk(lines, 2), func(chunk []string) *models.CommitFile {
return lo.Map(lo.Chunk(lines, 2), func(chunk []string, _ int) *models.CommitFile {
return &models.CommitFile{
ChangeStatus: chunk[0],
Name: chunk[1],

View File

@@ -6,16 +6,18 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"sync"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
// context:
@@ -33,11 +35,6 @@ type CommitLoader struct {
readFile func(filename string) ([]byte, error)
walkFiles func(root string, fn filepath.WalkFunc) error
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
}
@@ -45,7 +42,6 @@ type CommitLoader struct {
func NewCommitLoader(
cmn *common.Common,
cmd oscommands.ICmdObjBuilder,
dotGitDir string,
getRebaseMode func() (enums.RebaseMode, error),
gitCommon *GitCommon,
) *CommitLoader {
@@ -55,8 +51,6 @@ func NewCommitLoader(
getRebaseMode: getRebaseMode,
readFile: os.ReadFile,
walkFiles: filepath.Walk,
dotGitDir: dotGitDir,
mainBranches: nil,
GitCommon: gitCommon,
}
}
@@ -64,10 +58,15 @@ func NewCommitLoader(
type GetCommitsOptions struct {
Limit bool
FilterPath string
FilterAuthor string
IncludeRebaseCommits bool
RefName string // e.g. "HEAD" or "my_branch"
RefForPushedStatus string // the ref to use for determining pushed/unpushed status
// determines if we show the whole git graph i.e. pass the '--all' flag
All bool
// If non-empty, show divergence from this ref (left-right log)
RefToShowDivergenceFrom string
MainBranches *MainBranches
}
// GetCommits obtains the commits of the current branch
@@ -84,31 +83,81 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
commits = append(commits, rebasingCommits...)
}
wg := sync.WaitGroup{}
wg.Add(2)
var logErr error
go utils.Safe(func() {
defer wg.Done()
logErr = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
commit := self.extractCommitFromLine(line, opts.RefToShowDivergenceFrom != "")
commits = append(commits, commit)
return false, nil
})
})
var ancestor string
var remoteAncestor string
go utils.Safe(func() {
defer wg.Done()
ancestor = opts.MainBranches.GetMergeBase(opts.RefName)
if opts.RefToShowDivergenceFrom != "" {
remoteAncestor = opts.MainBranches.GetMergeBase(opts.RefToShowDivergenceFrom)
}
})
passedFirstPushedCommit := false
firstPushedCommit, err := self.getFirstPushedCommit(opts.RefName)
// I can get this before
firstPushedCommit, err := self.getFirstPushedCommit(opts.RefForPushedStatus)
if err != nil {
// must have no upstream branch so we'll consider everything as pushed
passedFirstPushedCommit = true
}
err = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
commit := self.extractCommitFromLine(line)
if commit.Sha == firstPushedCommit {
wg.Wait()
if logErr != nil {
return nil, logErr
}
for _, commit := range commits {
if commit.Hash == firstPushedCommit {
passedFirstPushedCommit = true
}
commit.Status = map[bool]models.CommitStatus{true: models.StatusUnpushed, false: models.StatusPushed}[!passedFirstPushedCommit]
commits = append(commits, commit)
return false, nil
})
if err != nil {
return nil, err
if commit.Status != models.StatusRebasing {
if passedFirstPushedCommit {
commit.Status = models.StatusPushed
} else {
commit.Status = models.StatusUnpushed
}
}
}
if len(commits) == 0 {
return commits, nil
}
commits = self.setCommitMergedStatuses(opts.RefName, commits)
if opts.RefToShowDivergenceFrom != "" {
sort.SliceStable(commits, func(i, j int) bool {
// In the divergence view we want incoming commits to come first
return commits[i].Divergence > commits[j].Divergence
})
_, localSectionStart, found := lo.FindIndexOf(commits, func(commit *models.Commit) bool {
return commit.Divergence == models.DivergenceLeft
})
if !found {
localSectionStart = len(commits)
}
setCommitMergedStatuses(remoteAncestor, commits[:localSectionStart])
setCommitMergedStatuses(ancestor, commits[localSectionStart:])
} else {
setCommitMergedStatuses(ancestor, commits)
}
return commits, nil
}
@@ -144,20 +193,24 @@ func (self *CommitLoader) MergeRebasingCommits(commits []*models.Commit) ([]*mod
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
// example input:
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
split := strings.SplitN(line, "\x00", 7)
func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool) *models.Commit {
split := strings.SplitN(line, "\x00", 8)
sha := split[0]
hash := split[0]
unixTimestamp := split[1]
authorName := split[2]
authorEmail := split[3]
extraInfo := strings.TrimSpace(split[4])
parentHashes := split[5]
message := split[6]
divergence := models.DivergenceNone
if showDivergence {
divergence = lo.Ternary(split[6] == "<", models.DivergenceLeft, models.DivergenceRight)
}
message := split[7]
tags := []string{}
@@ -183,7 +236,7 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
}
return &models.Commit{
Sha: sha,
Hash: hash,
Name: message,
Tags: tags,
ExtraInfo: extraInfo,
@@ -191,21 +244,19 @@ func (self *CommitLoader) extractCommitFromLine(line string) *models.Commit {
AuthorName: authorName,
AuthorEmail: authorEmail,
Parents: parents,
Divergence: divergence,
}
}
func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
commits, err := self.getRebasingCommits(rebaseMode)
if err != nil {
return nil, err
}
commits := self.getRebasingCommits(rebaseMode)
if len(commits) == 0 {
return nil, nil
}
commitShas := slices.FilterMap(commits, func(commit *models.Commit) (string, bool) {
return commit.Sha, commit.Sha != ""
commitHashes := lo.FilterMap(commits, func(commit *models.Commit, _ int) (string, bool) {
return commit.Hash, commit.Hash != ""
})
// note that we're not filtering these as we do non-rebasing commits just because
@@ -214,14 +265,14 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
NewGitCmd("show").
Config("log.showSignature=false").
Arg("--no-patch", "--oneline", "--abbrev=20", prettyFormat).
Arg(commitShas...).
Arg(commitHashes...).
ToArgv(),
).DontLog()
fullCommits := map[string]*models.Commit{}
err = cmdObj.RunAndProcessLines(func(line string) (bool, error) {
commit := self.extractCommitFromLine(line)
fullCommits[commit.Sha] = commit
err := cmdObj.RunAndProcessLines(func(line string) (bool, error) {
commit := self.extractCommitFromLine(line, false)
fullCommits[commit.Hash] = commit
return false, nil
})
if err != nil {
@@ -229,23 +280,23 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
}
findFullCommit := lo.Ternary(self.version.IsOlderThan(2, 25, 2),
func(sha string) *models.Commit {
func(hash string) *models.Commit {
for s, c := range fullCommits {
if strings.HasPrefix(s, sha) {
if strings.HasPrefix(s, hash) {
return c
}
}
return nil
},
func(sha string) *models.Commit {
return fullCommits[sha]
func(hash string) *models.Commit {
return fullCommits[hash]
})
hydratedCommits := make([]*models.Commit, 0, len(commits))
for _, rebasingCommit := range commits {
if rebasingCommit.Sha == "" {
if rebasingCommit.Hash == "" {
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.Status = rebasingCommit.Status
hydratedCommits = append(hydratedCommits, commit)
@@ -255,73 +306,20 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
}
// getRebasingCommits obtains the commits that we're in the process of rebasing
func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) ([]*models.Commit, error) {
switch rebaseMode {
case enums.REBASE_MODE_MERGING:
return self.getNormalRebasingCommits()
case enums.REBASE_MODE_INTERACTIVE:
return self.getInteractiveRebasingCommits()
default:
return nil, nil
}
}
func (self *CommitLoader) getNormalRebasingCommits() ([]*models.Commit, error) {
rewrittenCount := 0
bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-apply/rewritten"))
if err == nil {
content := string(bytesContent)
rewrittenCount = len(strings.Split(content, "\n"))
}
// we know we're rebasing, so lets get all the files whose names have numbers
commits := []*models.Commit{}
err = self.walkFiles(filepath.Join(self.dotGitDir, "rebase-apply"), func(path string, f os.FileInfo, err error) error {
if rewrittenCount > 0 {
rewrittenCount--
return nil
}
if err != nil {
return err
}
re := regexp.MustCompile(`^\d+$`)
if !re.MatchString(f.Name()) {
return nil
}
bytesContent, err := self.readFile(path)
if err != nil {
return err
}
content := string(bytesContent)
commit := self.commitFromPatch(content)
commits = append([]*models.Commit{commit}, commits...)
return nil
})
if err != nil {
return nil, err
}
return commits, nil
}
// git-rebase-todo example:
// pick ac446ae94ee560bdb8d1d057278657b251aaef17 ac446ae
// 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.dotGitDir, "rebase-merge/git-rebase-todo"))
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"))
if err != nil {
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
return nil, nil
return nil
}
commits := []*models.Commit{}
@@ -329,14 +327,14 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err
todos, err := todo.Parse(bytes.NewBuffer(bytesContent), self.config.GetCoreCommentChar())
if err != nil {
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
// so, add a fake entry for it
if conflictedCommitSha := self.getConflictedCommit(todos); conflictedCommitSha != "" {
if conflictedCommitHash := self.getConflictedCommit(todos); conflictedCommitHash != "" {
commits = append(commits, &models.Commit{
Sha: conflictedCommitSha,
Hash: conflictedCommitHash,
Name: "",
Status: models.StatusRebasing,
Action: models.ActionConflict,
@@ -345,24 +343,26 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err
for _, t := range todos {
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 == "" {
// Command does not have a commit associated, skip
continue
}
commits = slices.Prepend(commits, &models.Commit{
Sha: t.Commit,
commits = utils.Prepend(commits, &models.Commit{
Hash: t.Commit,
Name: t.Msg,
Status: models.StatusRebasing,
Action: t.Command,
})
}
return commits, nil
return commits
}
func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
bytesContent, err := self.readFile(filepath.Join(self.dotGitDir, "rebase-merge/done"))
bytesContent, err := self.readFile(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/done"))
if err != nil {
self.Log.Error(fmt.Sprintf("error occurred reading rebase-merge/done: %s", err.Error()))
return ""
@@ -375,7 +375,7 @@ func (self *CommitLoader) getConflictedCommit(todos []todo.Todo) string {
}
amendFileExists := false
if _, err := os.Stat(filepath.Join(self.dotGitDir, "rebase-merge/amend")); err == nil {
if _, err := os.Stat(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/amend")); err == nil {
amendFileExists = true
}
@@ -448,30 +448,15 @@ func (self *CommitLoader) getConflictedCommitImpl(todos []todo.Todo, doneTodos [
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 (self *CommitLoader) setCommitMergedStatuses(refName string, commits []*models.Commit) []*models.Commit {
ancestor := self.getMergeBase(refName)
func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
if ancestor == "" {
return commits
return
}
passedAncestor := false
for i, commit := range commits {
if strings.HasPrefix(ancestor, commit.Sha) {
// some commits aren't really commits and don't have hashes, such as the update-ref todo
if commit.Hash != "" && strings.HasPrefix(ancestor, commit.Hash) {
passedAncestor = true
}
if commit.Status != models.StatusPushed && commit.Status != models.StatusUnpushed {
@@ -481,65 +466,6 @@ func (self *CommitLoader) setCommitMergedStatuses(refName string, commits []*mod
commits[i].Status = models.StatusMerged
}
}
return commits
}
func (self *CommitLoader) getMergeBase(refName string) string {
if self.mainBranches == nil {
self.mainBranches = self.getExistingMainBranches()
}
if len(self.mainBranches) == 0 {
return ""
}
// We pass all configured main branches to the merge-base call; git will
// return the base commit for the closest one.
output, err := self.cmd.New(
NewGitCmd("merge-base").Arg(refName).Arg(self.mainBranches...).
ToArgv(),
).DontLog().RunWithOutput()
if err != nil {
// If there's an error, it must be because one of the main branches that
// used to exist when we called getExistingMainBranches() was deleted
// meanwhile. To fix this for next time, throw away our cache.
self.mainBranches = nil
}
return ignoringWarnings(output)
}
func (self *CommitLoader) getExistingMainBranches() []string {
return lo.FilterMap(self.UserConfig.Git.MainBranches,
func(branchName string, _ int) (string, bool) {
// Try to determine upstream of local main branch
if ref, err := self.cmd.New(
NewGitCmd("rev-parse").Arg("--symbolic-full-name", branchName+"@{u}").ToArgv(),
).DontLog().RunWithOutput(); err == nil {
return strings.TrimSpace(ref), true
}
// If this failed, a local branch for this main branch doesn't exist or it
// has no upstream configured. Try looking for one in the "origin" remote.
ref := "refs/remotes/origin/" + branchName
if err := self.cmd.New(
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
).DontLog().Run(); err == nil {
return ref, true
}
// If this failed as well, try if we have the main branch as a local
// branch. This covers the case where somebody is using git locally
// for something, but never pushing anywhere.
ref = "refs/heads/" + branchName
if err := self.cmd.New(
NewGitCmd("rev-parse").Arg("--verify", "--quiet", ref).ToArgv(),
).DontLog().Run(); err == nil {
return ref, true
}
return "", false
})
}
func ignoringWarnings(commandOutput string) string {
@@ -552,7 +478,7 @@ func ignoringWarnings(commandOutput string) string {
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.
func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
output, err := self.cmd.New(
@@ -572,18 +498,25 @@ func (self *CommitLoader) getFirstPushedCommit(refName string) (string, error) {
// getLog gets the git log.
func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
config := self.UserConfig.Git.Log
gitLogOrder := self.AppState.GitLogOrder
refSpec := opts.RefName
if opts.RefToShowDivergenceFrom != "" {
refSpec += "..." + opts.RefToShowDivergenceFrom
}
cmdArgs := NewGitCmd("log").
Arg(opts.RefName).
ArgIf(config.Order != "default", "--"+config.Order).
Arg(refSpec).
ArgIf(gitLogOrder != "default", "--"+gitLogOrder).
ArgIf(opts.All, "--all").
Arg("--oneline").
Arg(prettyFormat).
Arg("--abbrev=40").
ArgIf(opts.FilterAuthor != "", "--author="+opts.FilterAuthor).
ArgIf(opts.Limit, "-300").
ArgIf(opts.FilterPath != "", "--follow").
Arg("--no-show-signature").
ArgIf(opts.RefToShowDivergenceFrom != "", "--left-right").
Arg("--").
ArgIf(opts.FilterPath != "", opts.FilterPath).
ToArgv()
@@ -591,4 +524,4 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
return self.cmd.New(cmdArgs).DontLog()
}
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s`
const prettyFormat = `--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s`

View File

@@ -1,29 +1,30 @@
package git_commands
import (
"errors"
"path/filepath"
"strings"
"testing"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stefanhaller/git-todo-parser/todo"
"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
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
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|WIP
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|WIP
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|WIP
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|WIP
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|refactoring the config struct`, "|", "\x00", -1)
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
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield|jessedduffield@gmail.com|tag: 123, tag: 456|d8084cd558925eb7c9c3|>|refactor
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|>|WIP
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|>|WIP
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|>|WIP
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|>|WIP
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) {
type scenario struct {
@@ -42,10 +43,10 @@ func TestGetCommits(t *testing.T) {
testName: "should return no commits if there are none",
logOrder: "topo-order",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
ExpectGitArgs([]string{"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%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
expectedCommits: []*models.Commit{},
expectedError: nil,
@@ -54,10 +55,10 @@ func TestGetCommits(t *testing.T) {
testName: "should use proper upstream name for branch",
logOrder: "topo-order",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "refs/heads/mybranch", RefForPushedStatus: "refs/heads/mybranch", IncludeRebaseCommits: false},
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"merge-base", "refs/heads/mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
ExpectGitArgs([]string{"log", "refs/heads/mybranch", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
expectedCommits: []*models.Commit{},
expectedError: nil,
@@ -66,13 +67,13 @@ func TestGetCommits(t *testing.T) {
testName: "should return commits if they are present",
logOrder: "topo-order",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
mainBranches: []string{"master", "main", "develop"},
runner: oscommands.NewFakeRunner(t).
// here it's seeing which commits are yet to be pushed
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
// here it's actually getting all the commits in a formatted form, one per line
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, commitsOutput, nil).
// here it's testing which of the configured main branches have an upstream
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
@@ -85,7 +86,7 @@ func TestGetCommits(t *testing.T) {
expectedCommits: []*models.Commit{
{
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Name: "better typing for rebase mode",
Status: models.StatusUnpushed,
Action: models.ActionNone,
@@ -99,7 +100,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
Hash: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
Name: "fix logging",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -113,7 +114,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
Hash: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
Name: "refactor",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -127,7 +128,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "d8084cd558925eb7c9c38afeed5725c21653ab90",
Hash: "d8084cd558925eb7c9c38afeed5725c21653ab90",
Name: "WIP",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -141,7 +142,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
Hash: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
Name: "WIP",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -155,7 +156,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
Hash: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
Name: "WIP",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -169,7 +170,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
Hash: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
Name: "WIP",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -183,7 +184,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
Hash: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
Name: "refactoring the config struct",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -203,13 +204,13 @@ func TestGetCommits(t *testing.T) {
testName: "should not call merge-base for mainBranches if none exist",
logOrder: "topo-order",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
mainBranches: []string{"master", "main"},
runner: oscommands.NewFakeRunner(t).
// here it's seeing which commits are yet to be pushed
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
// here it's actually getting all the commits in a formatted form, one per line
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
// here it's testing which of the configured main branches exist; neither does
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")).
@@ -220,7 +221,7 @@ func TestGetCommits(t *testing.T) {
expectedCommits: []*models.Commit{
{
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Name: "better typing for rebase mode",
Status: models.StatusUnpushed,
Action: models.ActionNone,
@@ -240,13 +241,13 @@ func TestGetCommits(t *testing.T) {
testName: "should call merge-base for all main branches that exist",
logOrder: "topo-order",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
mainBranches: []string{"master", "main", "develop", "1.0-hotfixes"},
runner: oscommands.NewFakeRunner(t).
// here it's seeing which commits are yet to be pushed
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"merge-base", "mybranch", "mybranch@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
// here it's actually getting all the commits in a formatted form, one per line
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
ExpectGitArgs([]string{"log", "HEAD", "--topo-order", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, singleCommitOutput, nil).
// here it's testing which of the configured main branches exist
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")).
@@ -259,7 +260,7 @@ func TestGetCommits(t *testing.T) {
expectedCommits: []*models.Commit{
{
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Hash: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Name: "better typing for rebase mode",
Status: models.StatusUnpushed,
Action: models.ActionNone,
@@ -279,10 +280,10 @@ func TestGetCommits(t *testing.T) {
testName: "should not specify order if `log.order` is `default`",
logOrder: "default",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", IncludeRebaseCommits: false},
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
ExpectGitArgs([]string{"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%m%x00%s", "--abbrev=40", "--no-show-signature", "--"}, "", nil),
expectedCommits: []*models.Commit{},
expectedError: nil,
@@ -291,10 +292,10 @@ func TestGetCommits(t *testing.T) {
testName: "should set filter path",
logOrder: "default",
rebaseMode: enums.REBASE_MODE_NONE,
opts: GetCommitsOptions{RefName: "HEAD", FilterPath: "src"},
opts: GetCommitsOptions{RefName: "HEAD", RefForPushedStatus: "mybranch", FilterPath: "src"},
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"merge-base", "HEAD", "HEAD@{u}"}, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
ExpectGitArgs([]string{"log", "HEAD", "--oneline", "--pretty=format:%H%x00%at%x00%aN%x00%ae%x00%D%x00%p%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
ExpectGitArgs([]string{"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%m%x00%s", "--abbrev=40", "--follow", "--no-show-signature", "--", "src"}, "", nil),
expectedCommits: []*models.Commit{},
expectedError: nil,
@@ -302,14 +303,15 @@ func TestGetCommits(t *testing.T) {
}
for _, scenario := range scenarios {
scenario := scenario
t.Run(scenario.testName, func(t *testing.T) {
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{
Common: common,
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
cmd: cmd,
getRebaseMode: func() (enums.RebaseMode, error) { return scenario.rebaseMode, nil },
dotGitDir: ".git",
readFile: func(filename string) ([]byte, error) {
@@ -320,8 +322,10 @@ func TestGetCommits(t *testing.T) {
},
}
common.UserConfig.Git.MainBranches = scenario.mainBranches
commits, err := builder.GetCommits(scenario.opts)
common.UserConfig().Git.MainBranches = scenario.mainBranches
opts := scenario.opts
opts.MainBranches = NewMainBranches(common, cmd)
commits, err := builder.GetCommits(opts)
assert.Equal(t, scenario.expectedCommits, commits)
assert.Equal(t, scenario.expectedError, err)
@@ -337,14 +341,14 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
todos []todo.Todo
doneTodos []todo.Todo
amendFileExists bool
expectedSha string
expectedHash string
}{
{
testName: "no done todos",
todos: []todo.Todo{},
doneTodos: []todo.Todo{},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "common case (conflict)",
@@ -360,7 +364,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
{
testName: "last command was 'break'",
@@ -369,7 +373,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
{Command: todo.Break},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "last command was 'exec'",
@@ -381,7 +385,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "last command was 'reword'",
@@ -390,7 +394,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
{Command: todo.Reword},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "'pick' was rescheduled",
@@ -407,7 +411,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "'pick' was rescheduled, buggy git version",
@@ -432,7 +436,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "conflicting 'pick' after 'exec'",
@@ -457,7 +461,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
{
testName: "'edit' with amend file",
@@ -469,7 +473,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: true,
expectedSha: "",
expectedHash: "",
},
{
testName: "'edit' without amend file",
@@ -481,7 +485,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
}
for _, scenario := range scenarios {
@@ -501,8 +505,56 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
}
sha := builder.getConflictedCommitImpl(scenario.todos, scenario.doneTodos, scenario.amendFileExists)
assert.Equal(t, scenario.expectedSha, sha)
hash := builder.getConflictedCommitImpl(scenario.todos, scenario.doneTodos, scenario.amendFileExists)
assert.Equal(t, scenario.expectedHash, hash)
})
}
}
func TestCommitLoader_setCommitMergedStatuses(t *testing.T) {
type scenario struct {
testName string
commits []*models.Commit
ancestor string
expectedCommits []*models.Commit
}
scenarios := []scenario{
{
testName: "basic",
commits: []*models.Commit{
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusPushed},
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
},
ancestor: "67890",
expectedCommits: []*models.Commit{
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Hash: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusMerged},
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusMerged},
},
},
{
testName: "with update-ref",
commits: []*models.Commit{
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
},
ancestor: "deadbeef",
expectedCommits: []*models.Commit{
{Hash: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Hash: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
{Hash: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
},
},
}
for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) {
expectedCommits := scenario.commits
setCommitMergedStatuses(scenario.ancestor, expectedCommits)
assert.Equal(t, scenario.expectedCommits, expectedCommits)
})
}
}

View File

@@ -10,28 +10,30 @@ import (
func TestCommitRewordCommit(t *testing.T) {
type scenario struct {
testName string
runner *oscommands.FakeCmdObjRunner
input string
testName string
runner *oscommands.FakeCmdObjRunner
summary string
description string
}
scenarios := []scenario{
{
"Single line reword",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test"}, "", nil),
"test",
"",
},
{
"Multi line reword",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test", "-m", "line 2\nline 3"}, "", nil),
"test\nline 2\nline 3",
"test",
"line 2\nline 3",
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildCommitCommands(commonDeps{runner: s.runner})
assert.NoError(t, instance.RewordLastCommit(s.input))
assert.NoError(t, instance.RewordLastCommit(s.summary, s.description).Run())
s.runner.CheckForMissingCalls()
})
}
@@ -50,7 +52,8 @@ func TestCommitResetToCommit(t *testing.T) {
func TestCommitCommitCmdObj(t *testing.T) {
type scenario struct {
testName string
message string
summary string
description string
configSignoff bool
configSkipHookPrefix string
expectedArgs []string
@@ -59,35 +62,36 @@ func TestCommitCommitCmdObj(t *testing.T) {
scenarios := []scenario{
{
testName: "Commit",
message: "test",
summary: "test",
configSignoff: false,
configSkipHookPrefix: "",
expectedArgs: []string{"commit", "-m", "test"},
},
{
testName: "Commit with --no-verify flag",
message: "WIP: test",
summary: "WIP: test",
configSignoff: false,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
},
{
testName: "Commit with multiline message",
message: "line1\nline2",
summary: "line1",
description: "line2",
configSignoff: false,
configSkipHookPrefix: "",
expectedArgs: []string{"commit", "-m", "line1", "-m", "line2"},
},
{
testName: "Commit with signoff",
message: "test",
summary: "test",
configSignoff: true,
configSkipHookPrefix: "",
expectedArgs: []string{"commit", "--signoff", "-m", "test"},
},
{
testName: "Commit with signoff and no-verify",
message: "WIP: test",
summary: "WIP: test",
configSignoff: true,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
@@ -95,7 +99,6 @@ func TestCommitCommitCmdObj(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
userConfig := config.GetDefaultConfig()
userConfig.Git.Commit.SignOff = s.configSignoff
@@ -104,7 +107,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
assert.NoError(t, instance.CommitCmdObj(s.message).Run())
assert.NoError(t, instance.CommitCmdObj(s.summary, s.description).Run())
runner.CheckForMissingCalls()
})
}
@@ -131,7 +134,6 @@ func TestCommitCommitEditorCmdObj(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
userConfig := config.GetDefaultConfig()
userConfig.Git.Commit.SignOff = s.configSignoff
@@ -148,7 +150,7 @@ func TestCommitCommitEditorCmdObj(t *testing.T) {
func TestCommitCreateFixupCommit(t *testing.T) {
type scenario struct {
testName string
sha string
hash string
runner *oscommands.FakeCmdObjRunner
test func(error)
}
@@ -156,7 +158,7 @@ func TestCommitCreateFixupCommit(t *testing.T) {
scenarios := []scenario{
{
testName: "valid case",
sha: "12345",
hash: "12345",
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"commit", "--fixup=12345"}, "", nil),
test: func(err error) {
@@ -166,10 +168,59 @@ func TestCommitCreateFixupCommit(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
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()
})
}
@@ -177,54 +228,88 @@ func TestCommitCreateFixupCommit(t *testing.T) {
func TestCommitShowCmdObj(t *testing.T) {
type scenario struct {
testName string
filterPath string
contextSize int
ignoreWhitespace bool
expected []string
testName string
filterPath string
contextSize uint64
similarityThreshold int
ignoreWhitespace bool
extDiffCmd string
expected []string
}
scenarios := []scenario{
{
testName: "Default case without filter path",
filterPath: "",
contextSize: 3,
ignoreWhitespace: false,
expected: []string{"show", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890"},
testName: "Default case without filter path",
filterPath: "",
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: false,
extDiffCmd: "",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
},
{
testName: "Default case with filter path",
filterPath: "file.txt",
contextSize: 3,
ignoreWhitespace: false,
expected: []string{"show", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--", "file.txt"},
testName: "Default case with filter path",
filterPath: "file.txt",
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: false,
extDiffCmd: "",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--", "file.txt"},
},
{
testName: "Show diff with custom context size",
filterPath: "",
contextSize: 77,
ignoreWhitespace: false,
expected: []string{"show", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890"},
testName: "Show diff with custom context size",
filterPath: "",
contextSize: 77,
similarityThreshold: 50,
ignoreWhitespace: false,
extDiffCmd: "",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
},
{
testName: "Show diff, ignoring whitespace",
filterPath: "",
contextSize: 77,
ignoreWhitespace: true,
expected: []string{"show", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space"},
testName: "Show diff with custom similarity threshold",
filterPath: "",
contextSize: 3,
similarityThreshold: 33,
ignoreWhitespace: false,
extDiffCmd: "",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=33%"},
},
{
testName: "Show diff, ignoring whitespace",
filterPath: "",
contextSize: 77,
similarityThreshold: 50,
ignoreWhitespace: true,
extDiffCmd: "",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--no-ext-diff", "--submodule", "--color=always", "--unified=77", "--stat", "--decorate", "-p", "1234567890", "--ignore-all-space", "--find-renames=50%"},
},
{
testName: "Show diff with external diff command",
filterPath: "",
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: false,
extDiffCmd: "difft --color=always",
expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%"},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
userConfig := config.GetDefaultConfig()
userConfig.Git.DiffContextSize = s.contextSize
userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd
appState := &config.AppState{}
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
appState.DiffContextSize = s.contextSize
appState.RenameSimilarityThreshold = s.similarityThreshold
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil)
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
repoPaths := RepoPaths{
worktreePath: "/path/to/worktree",
}
instance := buildCommitCommands(commonDeps{userConfig: userConfig, appState: appState, runner: runner, repoPaths: &repoPaths})
assert.NoError(t, instance.ShowCmdObj("1234567890", s.filterPath, s.ignoreWhitespace).Run())
assert.NoError(t, instance.ShowCmdObj("1234567890", s.filterPath).Run())
runner.CheckForMissingCalls()
})
}
@@ -239,19 +324,17 @@ func TestGetCommitMsg(t *testing.T) {
scenarios := []scenario{
{
"empty",
` commit deadbeef`,
``,
``,
},
{
"no line breaks (single line)",
`commit deadbeef
use generics to DRY up context code`,
`use generics to DRY up context code`,
`use generics to DRY up context code`,
},
{
"with line breaks",
`commit deadbeef
Merge pull request #1750 from mark2185/fix-issue-template
`Merge pull request #1750 from mark2185/fix-issue-template
'git-rev parse' should be 'git rev-parse'`,
`Merge pull request #1750 from mark2185/fix-issue-template
@@ -261,10 +344,9 @@ Merge pull request #1750 from mark2185/fix-issue-template
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildCommitCommands(commonDeps{
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
})
output, err := instance.GetCommitMessage("deadbeef")
@@ -285,15 +367,14 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
scenarios := []scenario{
{
"Empty message",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1"}, "", nil),
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1"}, "", nil),
func(output string, err error) {
assert.Error(t, err)
},
},
{
"Default case to retrieve a commit in history",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "sha3 \n", nil).ExpectGitArgs([]string{"rev-list", "--format=%B", "--max-count=1", "sha3"}, `commit sha3
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) {
assert.NoError(t, err)
assert.Equal(t, "use generics to DRY up context code", output)
@@ -302,7 +383,6 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildCommitCommands(commonDeps{runner: s.runner})
@@ -312,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)
})
}
}

View File

@@ -4,7 +4,6 @@ import (
gogit "github.com/jesseduffield/go-git/v5"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/sasha-s/go-deadlock"
)
type GitCommon struct {
@@ -12,11 +11,9 @@ type GitCommon struct {
version *GitVersion
cmd oscommands.ICmdObjBuilder
os *oscommands.OSCommand
dotGitDir string
repoPaths *RepoPaths
repo *gogit.Repository
config *ConfigCommands
// mutex for doing things like push/pull/fetch
syncMutex *deadlock.Mutex
}
func NewGitCommon(
@@ -24,19 +21,17 @@ func NewGitCommon(
version *GitVersion,
cmd oscommands.ICmdObjBuilder,
osCommand *oscommands.OSCommand,
dotGitDir string,
repoPaths *RepoPaths,
repo *gogit.Repository,
config *ConfigCommands,
syncMutex *deadlock.Mutex,
) *GitCommon {
return &GitCommon{
Common: cmn,
version: version,
cmd: cmd,
os: osCommand,
dotGitDir: dotGitDir,
repoPaths: repoPaths,
repo: repo,
config: config,
syncMutex: syncMutex,
}
}

View File

@@ -43,7 +43,7 @@ func (self *ConfigCommands) ConfiguredPager() string {
}
func (self *ConfigCommands) GetPager(width int) string {
useConfig := self.UserConfig.Git.Paging.UseConfig
useConfig := self.UserConfig().Git.Paging.UseConfig
if useConfig {
pager := self.ConfiguredPager()
return strings.Split(pager, "| less")[0]
@@ -53,14 +53,14 @@ func (self *ConfigCommands) GetPager(width int) string {
"columnWidth": strconv.Itoa(width/2 - 6),
}
pagerTemplate := self.UserConfig.Git.Paging.Pager
pagerTemplate := string(self.UserConfig().Git.Paging.Pager)
return utils.ResolvePlaceholderString(pagerTemplate, templateValues)
}
// 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
func (self *ConfigCommands) UsingGpg() bool {
overrideGpg := self.UserConfig.Git.OverrideGpg
overrideGpg := self.UserConfig().Git.OverrideGpg
if overrideGpg {
return false
}
@@ -107,3 +107,7 @@ func (self *ConfigCommands) GetCoreCommentChar() byte {
return '#'
}
func (self *ConfigCommands) GetRebaseUpdateRefs() bool {
return self.gitConfig.GetBool("rebase.updateRefs")
}

View File

@@ -11,18 +11,21 @@ import (
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero"
)
type commonDeps struct {
runner *oscommands.FakeCmdObjRunner
userConfig *config.UserConfig
appState *config.AppState
gitVersion *GitVersion
gitConfig *git_config.FakeGitConfig
getenv func(string) string
removeFile func(string) error
dotGitDir string
common *common.Common
cmd *oscommands.CmdObjBuilder
fs afero.Fs
repoPaths *RepoPaths
}
func buildGitCommon(deps commonDeps) *GitCommon {
@@ -30,7 +33,17 @@ func buildGitCommon(deps commonDeps) *GitCommon {
gitCommon.Common = deps.common
if gitCommon.Common == nil {
gitCommon.Common = utils.NewDummyCommonWithUserConfig(deps.userConfig)
gitCommon.Common = utils.NewDummyCommonWithUserConfigAndAppState(deps.userConfig, deps.appState)
}
if deps.fs != nil {
gitCommon.Fs = deps.fs
}
if deps.repoPaths != nil {
gitCommon.repoPaths = deps.repoPaths
} else {
gitCommon.repoPaths = MockRepoPaths(".git")
}
runner := deps.runner
@@ -45,9 +58,9 @@ func buildGitCommon(deps commonDeps) *GitCommon {
}
gitCommon.cmd = cmd
gitCommon.Common.UserConfig = deps.userConfig
if gitCommon.Common.UserConfig == nil {
gitCommon.Common.UserConfig = config.GetDefaultConfig()
gitCommon.Common.SetUserConfig(deps.userConfig)
if gitCommon.Common.UserConfig() == nil {
gitCommon.Common.SetUserConfig(config.GetDefaultConfig())
}
gitCommon.version = deps.gitVersion
@@ -81,11 +94,6 @@ func buildGitCommon(deps commonDeps) *GitCommon {
TempDir: os.TempDir(),
})
gitCommon.dotGitDir = deps.dotGitDir
if gitCommon.dotGitDir == "" {
gitCommon.dotGitDir = ".git"
}
return gitCommon
}
@@ -96,7 +104,7 @@ func buildRepo() *gogit.Repository {
}
func buildFileLoader(gitCommon *GitCommon) *FileLoader {
return NewFileLoader(gitCommon.Common, gitCommon.cmd, gitCommon.config)
return NewFileLoader(gitCommon, gitCommon.cmd, gitCommon.config)
}
func buildSubmoduleCommands(deps commonDeps) *SubmoduleCommands {
@@ -118,7 +126,7 @@ func buildWorkingTreeCommands(deps commonDeps) *WorkingTreeCommands {
return NewWorkingTreeCommands(gitCommon, submoduleCommands, fileLoader)
}
func buildPatchCommands(deps commonDeps) *PatchCommands {
func buildPatchCommands(deps commonDeps) *PatchCommands { //nolint:golint,unused
gitCommon := buildGitCommon(deps)
rebaseCommands := buildRebaseCommands(deps)
commitCommands := buildCommitCommands(deps)
@@ -132,7 +140,7 @@ func buildPatchCommands(deps commonDeps) *PatchCommands {
return NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchBuilder)
}
func buildStatusCommands(deps commonDeps) *StatusCommands {
func buildStatusCommands(deps commonDeps) *StatusCommands { //nolint:golint,unused
gitCommon := buildGitCommon(deps)
return NewStatusCommands(gitCommon)

View File

@@ -1,6 +1,10 @@
package git_commands
import "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
)
type DiffCommands struct {
*GitCommon
@@ -12,8 +16,90 @@ 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 {
extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand
useExtDiff := extDiffCmd != ""
ignoreWhitespace := self.AppState.IgnoreWhitespaceInDiffView
return self.cmd.New(
NewGitCmd("diff").Arg("--submodule", "--no-ext-diff", "--color").Arg(diffArgs...).ToArgv(),
NewGitCmd("diff").
Config("diff.noprefix=false").
ConfigIf(useExtDiff, "diff.external="+extDiffCmd).
ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff").
Arg("--submodule").
Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)).
ArgIf(ignoreWhitespace, "--ignore-all-space").
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
Arg(diffArgs...).
Dir(self.repoPaths.worktreePath).
ToArgv(),
)
}
// This is a basic generic diff command that can be used for any diff operation
// (e.g. copying a diff to the clipboard). It will not use a custom pager, and
// does not use user configs such as ignore whitespace.
// If you want to diff specific refs (one or two), you need to add them yourself
// 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) GetDiff(staged bool, additionalArgs ...string) (string, error) {
return self.cmd.New(
NewGitCmd("diff").
Config("diff.noprefix=false").
Arg("--no-ext-diff", "--no-color").
ArgIf(staged, "--staged").
Dir(self.repoPaths.worktreePath).
Arg(additionalArgs...).
ToArgv(),
).RunWithOutput()
}
type DiffToolCmdOptions struct {
// The path to show a diff for. Pass "." for the entire repo.
Filepath string
// The commit against which to show the diff. Leave empty to show a diff of
// the working copy.
FromCommit string
// The commit to diff against FromCommit. Leave empty to diff the working
// copy against FromCommit. Leave both FromCommit and ToCommit empty to show
// the diff of the unstaged working copy changes against the index if Staged
// is false, or the staged changes against HEAD if Staged is true.
ToCommit string
// Whether to reverse the left and right sides of the diff.
Reverse bool
// Whether the given Filepath is a directory. We'll pass --dir-diff to
// git-difftool in that case.
IsDirectory bool
// Whether to show the staged or the unstaged changes. Must be false if both
// FromCommit and ToCommit are non-empty.
Staged bool
}
func (self *DiffCommands) OpenDiffToolCmdObj(opts DiffToolCmdOptions) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("difftool").
Arg("--no-prompt").
ArgIf(opts.IsDirectory, "--dir-diff").
ArgIf(opts.Staged, "--cached").
ArgIf(opts.FromCommit != "", opts.FromCommit).
ArgIf(opts.ToCommit != "", opts.ToCommit).
ArgIf(opts.Reverse, "-R").
Arg("--", opts.Filepath).
ToArgv())
}
func (self *DiffCommands) DiffIndexCmdObj(diffArgs ...string) oscommands.ICmdObj {
return self.cmd.New(
NewGitCmd("diff-index").
Config("diff.noprefix=false").
Arg("--submodule", "--no-ext-diff", "--no-color", "--patch").
Arg(diffArgs...).ToArgv(),
)
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
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) {
editor := self.UserConfig.OS.EditCommand
editor := self.UserConfig().OS.EditCommand
if editor == "" {
editor = self.config.GetCoreEditor()
@@ -59,7 +60,7 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (
"line": strconv.Itoa(lineNumber),
}
editCmdTemplate := self.UserConfig.OS.EditCommandTemplate
editCmdTemplate := self.UserConfig().OS.EditCommandTemplate
if len(editCmdTemplate) == 0 {
switch editor {
case "emacs", "nano", "vi", "vim", "nvim":
@@ -75,33 +76,36 @@ func (self *FileCommands) GetEditCmdStrLegacy(filename string, lineNumber int) (
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
if self.UserConfig.OS.Edit == "" && self.UserConfig.OS.EditCommandTemplate != "" {
if cmdStr, err := self.GetEditCmdStrLegacy(filename, 1); err == nil {
if self.UserConfig().OS.Edit == "" && self.UserConfig().OS.EditCommandTemplate != "" {
// 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
}
}
template, editInTerminal := config.GetEditTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
template, suspend := config.GetEditTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
quotedFilenames := lo.Map(filenames, func(filename string, _ int) string { return self.cmd.Quote(filename) })
templateValues := map[string]string{
"filename": self.cmd.Quote(filename),
"filename": strings.Join(quotedFilenames, " "),
}
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
return cmdStr, editInTerminal
return cmdStr, suspend
}
func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (string, bool) {
// 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 {
return cmdStr, true
}
}
template, editInTerminal := config.GetEditAtLineTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
template, suspend := config.GetEditAtLineTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
templateValues := map[string]string{
"filename": self.cmd.Quote(filename),
@@ -109,18 +113,18 @@ func (self *FileCommands) GetEditAtLineCmdStr(filename string, lineNumber int) (
}
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
return cmdStr, editInTerminal
return cmdStr, suspend
}
func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber int) string {
// 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 {
return cmdStr
}
}
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig.OS, self.guessDefaultEditor)
template := config.GetEditAtLineAndWaitTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
templateValues := map[string]string{
"filename": self.cmd.Quote(filename),
@@ -131,6 +135,17 @@ func (self *FileCommands) GetEditAtLineAndWaitCmdStr(filename string, lineNumber
return cmdStr
}
func (self *FileCommands) GetOpenDirInEditorCmdStr(path string) (string, bool) {
template, suspend := config.GetOpenDirInEditorTemplate(&self.UserConfig().OS, self.guessDefaultEditor)
templateValues := map[string]string{
"dir": self.cmd.Quote(path),
}
cmdStr := utils.ResolvePlaceholderString(template, templateValues)
return cmdStr, suspend
}
func (self *FileCommands) guessDefaultEditor() string {
// Try to query a few places where editors get configured
editor := self.config.GetCoreEditor()

View File

@@ -2,11 +2,12 @@ package git_commands
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
)
type FileLoaderConfig interface {
@@ -14,15 +15,15 @@ type FileLoaderConfig interface {
}
type FileLoader struct {
*common.Common
*GitCommon
cmd oscommands.ICmdObjBuilder
config FileLoaderConfig
getFileType func(string) string
}
func NewFileLoader(cmn *common.Common, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
func NewFileLoader(gitCommon *GitCommon, cmd oscommands.ICmdObjBuilder, config FileLoaderConfig) *FileLoader {
return &FileLoader{
Common: cmn,
GitCommon: gitCommon,
cmd: cmd,
getFileType: oscommands.FileType,
config: config,
@@ -31,13 +32,17 @@ func NewFileLoader(cmn *common.Common, cmd oscommands.ICmdObjBuilder, config Fil
type GetStatusFileOptions struct {
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 {
// check if config wants us ignoring untracked files
untrackedFilesSetting := self.config.GetShowUntrackedFiles()
if untrackedFilesSetting == "" {
if opts.ForceShowUntracked || untrackedFilesSetting == "" {
untrackedFilesSetting = "all"
}
untrackedFilesArg := fmt.Sprintf("--untracked-files=%s", untrackedFilesSetting)
@@ -48,6 +53,14 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*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 {
if strings.HasPrefix(status.StatusString, "warning") {
self.Log.Warningf("warning when calling git status: %s", status.StatusString)
@@ -58,16 +71,79 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File
Name: status.Name,
PreviousName: status.PreviousName,
DisplayString: status.StatusString,
Type: self.getFileType(status.Name),
}
if diff, ok := fileDiffs[status.Name]; ok {
file.LinesAdded = diff.LinesAdded
file.LinesDeleted = diff.LinesDeleted
}
models.SetStatusFields(file, status.Change)
files = append(files, file)
}
// Go through the files to see if any of these files are actually worktrees
// so that we can render them correctly
worktreePaths := linkedWortkreePaths(self.Fs, self.repoPaths.RepoGitDirPath())
for _, file := range files {
for _, worktreePath := range worktreePaths {
absFilePath, err := filepath.Abs(file.Name)
if err != nil {
self.Log.Error(err)
continue
}
if absFilePath == worktreePath {
file.IsWorktree = true
// `git status` renders this worktree as a folder with a trailing slash but we'll represent it as a singular worktree
// If we include the slash, it will be rendered as a folder with a null file inside.
file.Name = strings.TrimSuffix(file.Name, "/")
break
}
}
}
return files
}
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
type GitStatusOptions struct {
NoRenames bool
@@ -81,15 +157,29 @@ type FileStatus struct {
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").
Arg(opts.UntrackedFilesArg).
Arg("--porcelain").
Arg("-z").
ArgIf(opts.NoRenames, "--no-renames").
ArgIfElse(
opts.NoRenames,
"--no-renames",
fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold),
).
ToArgv()
statusLines, _, err := c.cmd.New(cmdArgs).DontLog().RunWithOutputs()
statusLines, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
if err != nil {
return []FileStatus{}, err
}

View File

@@ -5,32 +5,41 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/stretchr/testify/assert"
)
func TestFileGetStatusFiles(t *testing.T) {
type scenario struct {
testName string
runner oscommands.ICmdObjRunner
expectedFiles []*models.File
testName string
similarityThreshold int
runner oscommands.ICmdObjRunner
showNumstatInFilesView bool
expectedFiles []*models.File
}
scenarios := []scenario{
{
"No files found",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "", nil),
[]*models.File{},
testName: "No files found",
similarityThreshold: 50,
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "", nil),
expectedFiles: []*models.File{},
},
{
"Several files found",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
testName: "Several files found",
similarityThreshold: 50,
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",
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",
HasStagedChanges: true,
@@ -41,8 +50,9 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM file1.txt",
Type: "file",
ShortStatus: "MM",
LinesAdded: 4,
LinesDeleted: 1,
},
{
Name: "file3.txt",
@@ -54,8 +64,9 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "A file3.txt",
Type: "file",
ShortStatus: "A ",
LinesAdded: 2,
LinesDeleted: 2,
},
{
Name: "file2.txt",
@@ -67,8 +78,9 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "AM file2.txt",
Type: "file",
ShortStatus: "AM",
LinesAdded: 1,
LinesDeleted: 0,
},
{
Name: "file4.txt",
@@ -80,8 +92,9 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? file4.txt",
Type: "file",
ShortStatus: "??",
LinesAdded: 0,
LinesDeleted: 2,
},
{
Name: "file5.txt",
@@ -93,16 +106,18 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: true,
HasInlineMergeConflicts: true,
DisplayString: "UU file5.txt",
Type: "file",
ShortStatus: "UU",
LinesAdded: 2,
LinesDeleted: 2,
},
},
},
{
"File with new line char",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"}, "MM a\nb.txt", nil),
[]*models.File{
testName: "File with new line char",
similarityThreshold: 50,
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"}, "MM a\nb.txt", nil),
expectedFiles: []*models.File{
{
Name: "a\nb.txt",
HasStagedChanges: true,
@@ -113,19 +128,19 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "MM a\nb.txt",
Type: "file",
ShortStatus: "MM",
},
},
},
{
"Renamed files",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
testName: "Renamed files",
similarityThreshold: 50,
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",
nil,
),
[]*models.File{
expectedFiles: []*models.File{
{
Name: "after1.txt",
PreviousName: "before1.txt",
@@ -137,7 +152,6 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "R before1.txt -> after1.txt",
Type: "file",
ShortStatus: "R ",
},
{
@@ -151,19 +165,19 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "RM before2.txt -> after2.txt",
Type: "file",
ShortStatus: "RM",
},
},
},
{
"File with arrow in name",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z"},
testName: "File with arrow in name",
similarityThreshold: 50,
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"status", "--untracked-files=yes", "--porcelain", "-z", "--find-renames=50%"},
`?? a -> b.txt`,
nil,
),
[]*models.File{
expectedFiles: []*models.File{
{
Name: "a -> b.txt",
HasStagedChanges: false,
@@ -174,7 +188,6 @@ func TestFileGetStatusFiles(t *testing.T) {
HasMergeConflicts: false,
HasInlineMergeConflicts: false,
DisplayString: "?? a -> b.txt",
Type: "file",
ShortStatus: "??",
},
},
@@ -182,12 +195,20 @@ func TestFileGetStatusFiles(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
appState := &config.AppState{}
appState.RenameSimilarityThreshold = s.similarityThreshold
userConfig := &config.UserConfig{
Gui: config.GuiConfig{
ShowNumstatInFilesView: s.showNumstatInFilesView,
},
}
loader := &FileLoader{
Common: utils.NewDummyCommon(),
GitCommon: buildGitCommon(commonDeps{appState: appState, userConfig: userConfig}),
cmd: cmd,
config: &FakeFileLoaderConfig{showUntrackedFiles: "yes"},
getFileType: func(string) string { return "file" },

View File

@@ -177,36 +177,44 @@ func TestEditFileCmdStrLegacy(t *testing.T) {
}
}
func TestEditFileCmd(t *testing.T) {
func TestEditFilesCmd(t *testing.T) {
type scenario struct {
filename string
osConfig config.OSConfig
expectedCmdStr string
expectedEditInTerminal bool
filenames []string
osConfig config.OSConfig
expectedCmdStr string
suspend bool
}
scenarios := []scenario{
{
filename: "test",
osConfig: config.OSConfig{},
expectedCmdStr: `vim -- "test"`,
expectedEditInTerminal: true,
filenames: []string{"test"},
osConfig: config.OSConfig{},
expectedCmdStr: `vim -- "test"`,
suspend: true,
},
{
filename: "test",
filenames: []string{"test"},
osConfig: config.OSConfig{
Edit: "nano {{filename}}",
},
expectedCmdStr: `nano "test"`,
expectedEditInTerminal: true,
expectedCmdStr: `nano "test"`,
suspend: true,
},
{
filename: "file/with space",
filenames: []string{"file/with space"},
osConfig: config.OSConfig{
EditPreset: "sublime",
},
expectedCmdStr: `subl -- "file/with space"`,
expectedEditInTerminal: false,
expectedCmdStr: `subl -- "file/with space"`,
suspend: false,
},
{
filenames: []string{"multiple", "files"},
osConfig: config.OSConfig{
EditPreset: "sublime",
},
expectedCmdStr: `subl -- "multiple" "files"`,
suspend: false,
},
}
@@ -218,28 +226,28 @@ func TestEditFileCmd(t *testing.T) {
userConfig: userConfig,
})
cmdStr, editInTerminal := instance.GetEditCmdStr(s.filename)
cmdStr, suspend := instance.GetEditCmdStr(s.filenames)
assert.Equal(t, s.expectedCmdStr, cmdStr)
assert.Equal(t, s.expectedEditInTerminal, editInTerminal)
assert.Equal(t, s.suspend, suspend)
}
}
func TestEditFileAtLineCmd(t *testing.T) {
type scenario struct {
filename string
lineNumber int
osConfig config.OSConfig
expectedCmdStr string
expectedEditInTerminal bool
filename string
lineNumber int
osConfig config.OSConfig
expectedCmdStr string
suspend bool
}
scenarios := []scenario{
{
filename: "test",
lineNumber: 42,
osConfig: config.OSConfig{},
expectedCmdStr: `vim +42 -- "test"`,
expectedEditInTerminal: true,
filename: "test",
lineNumber: 42,
osConfig: config.OSConfig{},
expectedCmdStr: `vim +42 -- "test"`,
suspend: true,
},
{
filename: "test",
@@ -247,8 +255,8 @@ func TestEditFileAtLineCmd(t *testing.T) {
osConfig: config.OSConfig{
EditAtLine: "nano +{{line}} {{filename}}",
},
expectedCmdStr: `nano +35 "test"`,
expectedEditInTerminal: true,
expectedCmdStr: `nano +35 "test"`,
suspend: true,
},
{
filename: "file/with space",
@@ -256,8 +264,8 @@ func TestEditFileAtLineCmd(t *testing.T) {
osConfig: config.OSConfig{
EditPreset: "sublime",
},
expectedCmdStr: `subl -- "file/with space":12`,
expectedEditInTerminal: false,
expectedCmdStr: `subl -- "file/with space":12`,
suspend: false,
},
}
@@ -269,9 +277,9 @@ func TestEditFileAtLineCmd(t *testing.T) {
userConfig: userConfig,
})
cmdStr, editInTerminal := instance.GetEditAtLineCmdStr(s.filename, s.lineNumber)
cmdStr, suspend := instance.GetEditAtLineCmdStr(s.filename, s.lineNumber)
assert.Equal(t, s.expectedCmdStr, cmdStr)
assert.Equal(t, s.expectedEditInTerminal, editInTerminal)
assert.Equal(t, s.suspend, suspend)
}
}

View File

@@ -23,7 +23,6 @@ func TestStartCmdObj(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildFlowCommands(commonDeps{})
@@ -69,7 +68,6 @@ func TestFinishCmdObj(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildFlowCommands(commonDeps{
gitConfig: git_config.NewFakeGitConfig(s.gitConfigMockResponses),

View File

@@ -1,6 +1,8 @@
package git_commands
import "strings"
import (
"strings"
)
// convenience struct for building git commands. Especially useful when
// including conditional args
@@ -42,9 +44,58 @@ func (self *GitCommandBuilder) Config(value string) *GitCommandBuilder {
return self
}
func (self *GitCommandBuilder) RepoPath(value string) *GitCommandBuilder {
func (self *GitCommandBuilder) ConfigIf(condition bool, ifTrue string) *GitCommandBuilder {
if condition {
self.Config(ifTrue)
}
return self
}
// the -C arg will make git do a `cd` to the directory before doing anything else
func (self *GitCommandBuilder) Dir(path string) *GitCommandBuilder {
// repo path comes before the command
self.args = append([]string{"-C", value}, self.args...)
self.args = append([]string{"-C", path}, self.args...)
return self
}
func (self *GitCommandBuilder) DirIf(condition bool, path string) *GitCommandBuilder {
if condition {
return self.Dir(path)
}
return self
}
// Note, you may prefer to use the Dir method instead of this one
func (self *GitCommandBuilder) Worktree(path string) *GitCommandBuilder {
// worktree arg comes before the command
self.args = append([]string{"--work-tree", path}, self.args...)
return self
}
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
func (self *GitCommandBuilder) GitDir(path string) *GitCommandBuilder {
// git dir arg comes before the command
self.args = append([]string{"--git-dir", path}, self.args...)
return self
}
func (self *GitCommandBuilder) GitDirIf(condition bool, path string) *GitCommandBuilder {
if condition {
return self.GitDir(path)
}
return self
}

View File

@@ -45,7 +45,7 @@ func TestGitCommandBuilder(t *testing.T) {
expected: []string{"git", "-c", "user.email=bar", "-c", "user.name=foo", "push"},
},
{
input: NewGitCmd("push").RepoPath("a/b/c").ToArgv(),
input: NewGitCmd("push").Dir("a/b/c").ToArgv(),
expected: []string{"git", "-C", "a/b/c", "push"},
},
}

View File

@@ -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
}

View File

@@ -1,17 +1,15 @@
package git_commands
import (
"fmt"
"path/filepath"
"time"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/app/daemon"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stefanhaller/git-todo-parser/todo"
)
type PatchCommands struct {
@@ -49,8 +47,8 @@ type ApplyPatchOpts struct {
Reverse bool
}
func (self *PatchCommands) ApplyCustomPatch(reverse bool) error {
patch := self.PatchBuilder.PatchToApply(reverse)
func (self *PatchCommands) ApplyCustomPatch(reverse bool, turnAddedFilesIntoDiffAgainstEmptyFile bool) error {
patch := self.PatchBuilder.PatchToApply(reverse, turnAddedFilesIntoDiffAgainstEmptyFile)
return self.ApplyPatch(patch, ApplyPatchOpts{
Index: true,
@@ -81,7 +79,7 @@ func (self *PatchCommands) applyPatchFile(filepath string, opts ApplyPatchOpts)
}
func (self *PatchCommands) SaveTemporaryPatch(patch string) (string, error) {
filepath := filepath.Join(self.os.GetTempDir(), utils.GetCurrentRepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
filepath := filepath.Join(self.os.GetTempDir(), self.repoPaths.RepoName(), time.Now().Format("Jan _2 15.04.05.000000000")+".patch")
self.Log.Infof("saving temporary patch to %s", filepath)
if err := self.os.CreateFileWithContent(filepath, patch); err != nil {
return "", err
@@ -96,7 +94,7 @@ func (self *PatchCommands) DeletePatchesFromCommit(commits []*models.Commit, com
}
// apply each patch in reverse
if err := self.ApplyCustomPatch(true); err != nil {
if err := self.ApplyCustomPatch(true, true); err != nil {
_ = self.rebase.AbortRebase()
return err
}
@@ -125,7 +123,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
}
// 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
// the user a chance to resolve them
return err
@@ -159,13 +157,13 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
baseIndex := sourceCommitIdx + 1
changes := []daemon.ChangeTodoAction{
{Sha: commits[sourceCommitIdx].Sha, NewAction: todo.Edit},
{Sha: commits[destinationCommitIdx].Sha, NewAction: todo.Edit},
{Hash: commits[sourceCommitIdx].Hash, NewAction: todo.Edit},
{Hash: commits[destinationCommitIdx].Hash, NewAction: todo.Edit},
}
self.os.LogCommand(logTodoChanges(changes), false)
err := self.rebase.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: commits[baseIndex].Sha,
baseHashOrRoot: commits[baseIndex].Hash,
overrideEditor: true,
instruction: daemon.NewChangeTodoActionsInstruction(changes),
}).Run()
@@ -174,7 +172,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
}
// apply each patch in reverse
if err := self.ApplyCustomPatch(true); err != nil {
if err := self.ApplyCustomPatch(true, true); err != nil {
_ = self.rebase.AbortRebase()
return err
}
@@ -221,7 +219,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitIdx int, stash bool) error {
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
}
}
@@ -230,7 +228,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
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 {
_ = self.rebase.AbortRebase()
}
@@ -274,12 +272,17 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
return self.rebase.ContinueRebase()
}
func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, commitIdx int) error {
func (self *PatchCommands) PullPatchIntoNewCommit(
commits []*models.Commit,
commitIdx int,
commitSummary string,
commitDescription string,
) error {
if err := self.rebase.BeginInteractiveRebaseForCommit(commits, commitIdx, false); err != nil {
return err
}
if err := self.ApplyCustomPatch(true); err != nil {
if err := self.ApplyCustomPatch(true, true); err != nil {
_ = self.rebase.AbortRebase()
return err
}
@@ -300,9 +303,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
return err
}
head_message, _ := self.commit.GetHeadCommitMessage()
new_message := fmt.Sprintf("Split from \"%s\"", head_message)
if err := self.commit.CommitCmdObj(new_message).Run(); err != nil {
if err := self.commit.CommitCmdObj(commitSummary, commitDescription).Run(); err != nil {
return err
}
@@ -320,7 +321,11 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
// only some lines of a range of adjacent added lines. To solve this, we
// get the diff of HEAD and the original commit and then apply that.
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()
}

View File

@@ -1,68 +0,0 @@
package git_commands
import (
"fmt"
"os"
"testing"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/stretchr/testify/assert"
)
func TestPatchApplyPatch(t *testing.T) {
type scenario struct {
testName string
opts ApplyPatchOpts
runner *oscommands.FakeCmdObjRunner
test func(error)
}
// expectedArgs excludes the last argument which is an indeterminate filename
expectFn := func(expectedArgs []string, errToReturn error) func(cmdObj oscommands.ICmdObj) (string, error) {
return func(cmdObj oscommands.ICmdObj) (string, error) {
args := cmdObj.Args()
assert.Equal(t, len(args), len(expectedArgs)+1, fmt.Sprintf("unexpected command: %s", cmdObj.ToString()))
filename := args[len(args)-1]
content, err := os.ReadFile(filename)
assert.NoError(t, err)
assert.Equal(t, "test", string(content))
return "", errToReturn
}
}
scenarios := []scenario{
{
testName: "valid case",
opts: ApplyPatchOpts{Cached: true},
runner: oscommands.NewFakeRunner(t).
ExpectFunc(expectFn([]string{"git", "apply", "--cached"}, nil)),
test: func(err error) {
assert.NoError(t, err)
},
},
{
testName: "command returns error",
opts: ApplyPatchOpts{Cached: true},
runner: oscommands.NewFakeRunner(t).
ExpectFunc(expectFn([]string{"git", "apply", "--cached"}, errors.New("error"))),
test: func(err error) {
assert.Error(t, err)
},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildPatchCommands(commonDeps{runner: s.runner})
s.test(instance.ApplyPatch("test", s.opts))
s.runner.CheckForMissingCalls()
})
}
}

View File

@@ -5,14 +5,13 @@ import (
"path/filepath"
"strings"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/go-errors/errors"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/app/daemon"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
type RebaseCommands struct {
@@ -35,10 +34,9 @@ func NewRebaseCommands(
}
}
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, message string) error {
if models.IsHeadCommit(commits, index) {
// we've selected the top commit so no rebase is required
return self.commit.RewordLastCommit(message)
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
if self.config.UsingGpg() {
return errors.New(self.Tr.DisabledForGPG)
}
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
@@ -47,7 +45,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, me
}
// now the selected commit should be our head so we'll amend it with the new message
err = self.commit.RewordLastCommit(message)
err = self.commit.RewordLastCommit(summary, description).Run()
if err != nil {
return err
}
@@ -57,115 +55,152 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, me
func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index int) (oscommands.ICmdObj, error) {
changes := []daemon.ChangeTodoAction{{
Sha: commits[index].Sha,
Hash: commits[index].Hash,
NewAction: todo.Reword,
}}
self.os.LogCommand(logTodoChanges(changes), false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: getBaseShaOrRoot(commits, index+1),
instruction: daemon.NewChangeTodoActionsInstruction(changes),
baseHashOrRoot: getBaseHashOrRoot(commits, index+1),
instruction: daemon.NewChangeTodoActionsInstruction(changes),
}), nil
}
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, index int) error {
return self.GenericAmend(commits, index, func() error {
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, start, end int) error {
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
return self.commit.ResetAuthor()
})
}
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, index int, value string) error {
return self.GenericAmend(commits, index, func() error {
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, start, end int, value string) error {
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
return self.commit.SetAuthor(value)
})
}
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f func() error) error {
if models.IsHeadCommit(commits, index) {
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, value string) error {
return self.GenericAmend(commits, start, end, func(commit *models.Commit) error {
return self.commit.AddCoAuthor(commit.Hash, value)
})
}
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, start, end int, f func(commit *models.Commit) error) error {
if start == end && models.IsHeadCommit(commits, start) {
// we've selected the top commit so no rebase is required
return f()
return f(commits[start])
}
err := self.BeginInteractiveRebaseForCommit(commits, index, false)
err := self.BeginInteractiveRebaseForCommitRange(commits, start, end, false)
if err != nil {
return err
}
// now the selected commit should be our head so we'll amend it
err = f()
if err != nil {
return err
for commitIndex := end; commitIndex >= start; commitIndex-- {
err = f(commits[commitIndex])
if err != nil {
return err
}
if err := self.ContinueRebase(); err != nil {
return err
}
}
return self.ContinueRebase()
return nil
}
func (self *RebaseCommands) MoveCommitDown(commits []*models.Commit, index int) error {
baseShaOrRoot := getBaseShaOrRoot(commits, index+2)
func (self *RebaseCommands) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+2)
sha := commits[index].Sha
self.os.LogCommand(fmt.Sprintf("Moving TODO down: %s", utils.ShortSha(sha)), false)
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Hash
})
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
instruction: daemon.NewMoveTodoDownInstruction(sha),
baseHashOrRoot: baseHashOrRoot,
instruction: daemon.NewMoveTodosDownInstruction(hashes),
overrideEditor: true,
}).Run()
}
func (self *RebaseCommands) MoveCommitUp(commits []*models.Commit, index int) error {
baseShaOrRoot := getBaseShaOrRoot(commits, index+1)
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+1)
sha := commits[index].Sha
self.os.LogCommand(fmt.Sprintf("Moving TODO up: %s", utils.ShortSha(sha)), false)
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Hash
})
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
instruction: daemon.NewMoveTodoUpInstruction(sha),
baseHashOrRoot: baseHashOrRoot,
instruction: daemon.NewMoveTodosUpInstruction(hashes),
overrideEditor: true,
}).Run()
}
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, index int, action todo.TodoCommand) error {
baseIndex := index + 1
func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx int, endIdx int, action todo.TodoCommand) error {
baseIndex := endIdx + 1
if action == todo.Squash || action == todo.Fixup {
baseIndex++
}
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
changes := lo.FilterMap(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) (daemon.ChangeTodoAction, bool) {
return daemon.ChangeTodoAction{
Hash: commit.Hash,
NewAction: action,
}, !commit.IsMerge()
})
changes := []daemon.ChangeTodoAction{{
Sha: commits[index].Sha,
NewAction: action,
}}
self.os.LogCommand(logTodoChanges(changes), false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
baseHashOrRoot: baseHashOrRoot,
overrideEditor: true,
instruction: daemon.NewChangeTodoActionsInstruction(changes),
}).Run()
}
func (self *RebaseCommands) EditRebase(branchRef string) error {
self.os.LogCommand(fmt.Sprintf("Beginning interactive rebase at '%s'", branchRef), false)
msg := utils.ResolvePlaceholderString(
self.Tr.Log.EditRebase,
map[string]string{
"ref": branchRef,
},
)
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: branchRef,
instruction: daemon.NewInsertBreakInstruction(),
baseHashOrRoot: branchRef,
instruction: daemon.NewInsertBreakInstruction(),
}).Run()
}
func (self *RebaseCommands) EditRebaseFromBaseCommit(targetBranchName string, baseCommit string) error {
msg := utils.ResolvePlaceholderString(
self.Tr.Log.EditRebaseFromBaseCommit,
map[string]string{
"baseCommit": baseCommit,
"targetBranchName": targetBranchName,
},
)
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseHashOrRoot: baseCommit,
onto: targetBranchName,
instruction: daemon.NewInsertBreakInstruction(),
}).Run()
}
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
changeTodoStr := strings.Join(slices.Map(changes, func(c daemon.ChangeTodoAction) string {
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
return fmt.Sprintf("%s:%s", c.Hash, c.NewAction)
}), "\n")
return fmt.Sprintf("Changing TODO actions: %s", changeTodoStr)
return fmt.Sprintf("Changing TODO actions:\n%s", changeTodoStr)
}
type PrepareInteractiveRebaseCommandOpts struct {
baseShaOrRoot string
baseHashOrRoot string
onto string
instruction daemon.Instruction
overrideEditor bool
keepCommitsThatBecomeEmpty bool
@@ -173,7 +208,7 @@ type PrepareInteractiveRebaseCommandOpts struct {
// PrepareInteractiveRebaseCommand returns the cmd for an interactive rebase
// 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 {
ex := oscommands.GetLazygitPath()
@@ -181,10 +216,11 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
Arg("--interactive").
Arg("--autostash").
Arg("--keep-empty").
ArgIf(opts.keepCommitsThatBecomeEmpty && !self.version.IsOlderThan(2, 26, 0), "--empty=keep").
ArgIf(opts.keepCommitsThatBecomeEmpty && self.version.IsAtLeast(2, 26, 0), "--empty=keep").
Arg("--no-autosquash").
ArgIf(!self.version.IsOlderThan(2, 22, 0), "--rebase-merges").
Arg(opts.baseShaOrRoot).
ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges").
ArgIf(opts.onto != "", "--onto", opts.onto).
Arg(opts.baseHashOrRoot).
ToArgv()
debug := "FALSE"
@@ -201,7 +237,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
if opts.instruction != nil {
cmdObj.AddEnvVars(daemon.ToEnvVars(opts.instruction)...)
} else {
gitSequenceEditor = "true"
cmdObj.AddEnvVars(daemon.ToEnvVars(daemon.NewRemoveUpdateRefsForCopiedBranchInstruction())...)
}
cmdObj.AddEnvVars(
@@ -218,55 +254,142 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
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
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
commit := commits[commitIndex]
if err := self.commit.CreateFixupCommit(commit.Sha); err != nil {
if err := self.commit.CreateFixupCommit(commit.Hash); err != nil {
return err
}
// Get the sha of the commit we just created
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
fixupSha, err := self.cmd.New(cmdArgs).RunWithOutput()
fixupHash, err := self.getHashOfLastCommitMade()
if err != nil {
return err
}
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: getBaseShaOrRoot(commits, commitIndex+1),
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
overrideEditor: true,
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Sha, fixupSha),
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Hash, fixupHash, true),
}).Run()
}
// EditRebaseTodo sets the action for a given rebase commit in the git-rebase-todo file
func (self *RebaseCommands) EditRebaseTodo(commit *models.Commit, action todo.TodoCommand) error {
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
func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo.TodoCommand) error {
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
return utils.TodoChange{
Hash: commit.Hash,
NewAction: action,
}
})
return utils.EditRebaseTodo(
filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo"), commit.Sha, commit.Action, action, self.config.GetCoreCommentChar())
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
commitsWithAction,
self.config.GetCoreCommentChar(),
)
}
// MoveTodoDown moves a rebase todo item down by one position
func (self *RebaseCommands) MoveTodoDown(commit *models.Commit) error {
fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
return utils.MoveTodoDown(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
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)
}
// MoveTodoDown moves a rebase todo item down by one position
func (self *RebaseCommands) MoveTodoUp(commit *models.Commit) error {
fileName := filepath.Join(self.dotGitDir, "rebase-merge/git-rebase-todo")
return utils.MoveTodoUp(fileName, commit.Sha, commit.Action, self.config.GetCoreCommentChar())
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
return todoFromCommit(commit)
})
return utils.MoveTodosDown(fileName, todosToMove, true, self.config.GetCoreCommentChar())
}
func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
fileName := filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo")
todosToMove := lo.Map(commits, func(commit *models.Commit, _ int) utils.Todo {
return todoFromCommit(commit)
})
return utils.MoveTodosUp(fileName, todosToMove, true, self.config.GetCoreCommentChar())
}
// SquashAllAboveFixupCommits squashes all fixup! commits above the given one
func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) error {
shaOrRoot := commit.Sha + "^"
hashOrRoot := commit.Hash + "^"
if commit.IsFirstCommit() {
shaOrRoot = "--root"
hashOrRoot = "--root"
}
cmdArgs := NewGitCmd("rebase").
Arg("--interactive", "--rebase-merges", "--autostash", "--autosquash", shaOrRoot).
Arg("--interactive", "--rebase-merges", "--autostash", "--autosquash", hashOrRoot).
ToArgv()
return self.runSkipEditorCommand(self.cmd.New(cmdArgs))
@@ -277,7 +400,13 @@ func (self *RebaseCommands) SquashAllAboveFixupCommits(commit *models.Commit) er
func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
commits []*models.Commit, commitIndex int, keepCommitsThatBecomeEmpty bool,
) 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")
}
@@ -288,14 +417,17 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
return errors.New(self.Tr.DisabledForGPG)
}
changes := []daemon.ChangeTodoAction{{
Sha: commits[commitIndex].Sha,
NewAction: todo.Edit,
}}
changes := make([]daemon.ChangeTodoAction, 0, end-start)
for commitIndex := end; commitIndex >= start; commitIndex-- {
changes = append(changes, daemon.ChangeTodoAction{
Hash: commits[commitIndex].Hash,
NewAction: todo.Edit,
})
}
self.os.LogCommand(logTodoChanges(changes), false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: getBaseShaOrRoot(commits, commitIndex+1),
baseHashOrRoot: getBaseHashOrRoot(commits, end+1),
overrideEditor: true,
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
instruction: daemon.NewChangeTodoActionsInstruction(changes),
@@ -304,7 +436,14 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
// RebaseBranch interactive rebases onto a branch
func (self *RebaseCommands) RebaseBranch(branchName string) error {
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseShaOrRoot: branchName}).Run()
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{baseHashOrRoot: branchName}).Run()
}
func (self *RebaseCommands) RebaseBranchFromBaseCommit(targetBranchName string, baseCommit string) error {
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseHashOrRoot: baseCommit,
onto: targetBranchName,
}).Run()
}
func (self *RebaseCommands) GenericMergeOrRebaseActionCmdObj(commandType string, command string) oscommands.ICmdObj {
@@ -361,23 +500,25 @@ func (self *RebaseCommands) runSkipEditorCommand(cmdObj oscommands.ICmdObj) erro
}
// 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 {
return err
}
// 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^:"+fileName).ToArgv()
for _, filePath := range filePaths {
// 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.os.Remove(fileName); err != nil {
if err := self.cmd.New(cmdArgs).Run(); 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
}
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
@@ -390,28 +531,55 @@ func (self *RebaseCommands) DiscardOldFileChanges(commits []*models.Commit, comm
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 {
commitLines := lo.Map(commits, func(commit *models.Commit, _ int) string {
return fmt.Sprintf("%s %s", utils.ShortSha(commit.Sha), commit.Name)
return fmt.Sprintf("%s %s", utils.ShortHash(commit.Hash), commit.Name)
})
self.os.LogCommand(fmt.Sprintf("Cherry-picking commits:\n%s", strings.Join(commitLines, "\n")), false)
msg := utils.ResolvePlaceholderString(
self.Tr.Log.CherryPickCommits,
map[string]string{
"commitLines": strings.Join(commitLines, "\n"),
},
)
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: "HEAD",
instruction: daemon.NewCherryPickCommitsInstruction(commits),
baseHashOrRoot: "HEAD",
instruction: daemon.NewCherryPickCommitsInstruction(commits),
}).Run()
}
// CherryPickCommitsDuringRebase simply prepends the given commits to the existing git-rebase-todo file
func (self *RebaseCommands) CherryPickCommitsDuringRebase(commits []*models.Commit) error {
todoLines := lo.Map(commits, func(commit *models.Commit, _ int) daemon.TodoLine {
return daemon.TodoLine{
Action: "pick",
Commit: commit,
}
})
todo := daemon.TodoLinesToString(todoLines)
filePath := filepath.Join(self.repoPaths.worktreeGitDirPath, "rebase-merge/git-rebase-todo")
return utils.PrependStrToTodoFile(filePath, []byte(todo))
}
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
// '--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.
// 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
// at time of writing)
if index < len(commits) {
return commits[index].Sha
return commits[index].Hash
} else {
return "--root"
}

View File

@@ -67,7 +67,6 @@ func TestRebaseRebaseBranch(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildRebaseCommands(commonDeps{runner: s.runner, gitVersion: s.gitVersion})
s.test(instance.RebaseBranch(s.arg))
@@ -79,7 +78,7 @@ func TestRebaseRebaseBranch(t *testing.T) {
// environment variables that suppress an interactive editor
func TestRebaseSkipEditorCommand(t *testing.T) {
cmdArgs := []string{"git", "blah"}
runner := oscommands.NewFakeRunner(t).ExpectFunc(func(cmdObj oscommands.ICmdObj) (string, error) {
runner := oscommands.NewFakeRunner(t).ExpectFunc("matches editor env var", func(cmdObj oscommands.ICmdObj) bool {
assert.EqualValues(t, cmdArgs, cmdObj.Args())
envVars := cmdObj.GetEnvVars()
for _, regexStr := range []string{
@@ -89,16 +88,15 @@ func TestRebaseSkipEditorCommand(t *testing.T) {
`^GIT_SEQUENCE_EDITOR=.*$`,
"^" + daemon.DaemonKindEnvKey + "=" + strconv.Itoa(int(daemon.DaemonKindExitImmediately)) + "$",
} {
regexStr := regexStr
foundMatch := lo.ContainsBy(envVars, func(envVar string) bool {
return regexp.MustCompile(regexStr).MatchString(envVar)
})
if !foundMatch {
t.Errorf("expected environment variable %s to be set", regexStr)
return false
}
}
return "", nil
})
return true
}, "", nil)
instance := buildRebaseCommands(commonDeps{runner: runner})
err := instance.runSkipEditorCommand(instance.cmd.New(cmdArgs))
assert.NoError(t, err)
@@ -111,7 +109,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
gitConfigMockResponses map[string]string
commits []*models.Commit
commitIndex int
fileName string
fileName []string
runner *oscommands.FakeCmdObjRunner
test func(error)
}
@@ -122,7 +120,7 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
gitConfigMockResponses: nil,
commits: []*models.Commit{},
commitIndex: 0,
fileName: "test999.txt",
fileName: []string{"test999.txt"},
runner: oscommands.NewFakeRunner(t),
test: func(err error) {
assert.Error(t, err)
@@ -131,9 +129,9 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
{
testName: "returns error when using gpg",
gitConfigMockResponses: map[string]string{"commit.gpgsign": "true"},
commits: []*models.Commit{{Name: "commit", Sha: "123456"}},
commits: []*models.Commit{{Name: "commit", Hash: "123456"}},
commitIndex: 0,
fileName: "test999.txt",
fileName: []string{"test999.txt"},
runner: oscommands.NewFakeRunner(t),
test: func(err error) {
assert.Error(t, err)
@@ -143,11 +141,11 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
testName: "checks out file if it already existed",
gitConfigMockResponses: nil,
commits: []*models.Commit{
{Name: "commit", Sha: "123456"},
{Name: "commit2", Sha: "abcdef"},
{Name: "commit", Hash: "123456"},
{Name: "commit2", Hash: "abcdef"},
},
commitIndex: 0,
fileName: "test999.txt",
fileName: []string{"test999.txt"},
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"rebase", "--interactive", "--autostash", "--keep-empty", "--no-autosquash", "--rebase-merges", "abcdef"}, "", nil).
ExpectGitArgs([]string{"cat-file", "-e", "HEAD^:test999.txt"}, "", nil).
@@ -163,7 +161,6 @@ func TestRebaseDiscardOldFileChanges(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildRebaseCommands(commonDeps{
runner: s.runner,

View File

@@ -23,7 +23,7 @@ func NewReflogCommitLoader(common *common.Common, cmd oscommands.ICmdObjBuilder)
// 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
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)
cmdArgs := NewGitCmd("log").
@@ -31,38 +31,24 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
Arg("-g").
Arg("--abbrev=40").
Arg("--format=%h%x00%ct%x00%gs%x00%p").
ArgIf(filterAuthor != "", "--author="+filterAuthor).
ArgIf(filterPath != "", "--follow", "--", filterPath).
ToArgv()
cmdObj := self.cmd.New(cmdArgs).DontLog()
onlyObtainedNewReflogCommits := false
err := cmdObj.RunAndProcessLines(func(line string) (bool, error) {
fields := strings.SplitN(line, "\x00", 4)
if len(fields) <= 3 {
commit, ok := self.parseLine(line)
if !ok {
return false, nil
}
unixTimestamp, _ := strconv.Atoi(fields[1])
parentHashes := fields[3]
parents := []string{}
if len(parentHashes) > 0 {
parents = strings.Split(parentHashes, " ")
}
commit := &models.Commit{
Sha: fields[0],
Name: fields[2],
UnixTimestamp: int64(unixTimestamp),
Status: models.StatusReflog,
Parents: parents,
}
// note that the unix timestamp here is the timestamp of the COMMIT, not the reflog entry itself,
// 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
// twice in a row. Reason being that it would mean we'd be erroneously exiting early.
if lastReflogCommit != nil && commit.Sha == lastReflogCommit.Sha && commit.UnixTimestamp == lastReflogCommit.UnixTimestamp && commit.Name == lastReflogCommit.Name {
if lastReflogCommit != nil && self.sameReflogCommit(commit, lastReflogCommit) {
onlyObtainedNewReflogCommits = true
// after this point we already have these reflogs loaded so we'll simply return the new ones
return true, nil
@@ -77,3 +63,30 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
return commits, onlyObtainedNewReflogCommits, nil
}
func (self *ReflogCommitLoader) sameReflogCommit(a *models.Commit, b *models.Commit) bool {
return a.Hash == b.Hash && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
}
func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
fields := strings.SplitN(line, "\x00", 4)
if len(fields) <= 3 {
return nil, false
}
unixTimestamp, _ := strconv.Atoi(fields[1])
parentHashes := fields[3]
parents := []string{}
if len(parentHashes) > 0 {
parents = strings.Split(parentHashes, " ")
}
return &models.Commit{
Hash: fields[0],
Name: fields[2],
UnixTimestamp: int64(unixTimestamp),
Status: models.StatusReflog,
Parents: parents,
}, true
}

View File

@@ -25,6 +25,7 @@ func TestGetReflogCommits(t *testing.T) {
runner *oscommands.FakeCmdObjRunner
lastReflogCommit *models.Commit
filterPath string
filterAuthor string
expectedCommits []*models.Commit
expectedOnlyObtainedNew bool
expectedError error
@@ -49,35 +50,35 @@ func TestGetReflogCommits(t *testing.T) {
lastReflogCommit: nil,
expectedCommits: []*models.Commit{
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from A to B",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
Parents: []string{"51baa8c1"},
},
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from B to A",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
Parents: []string{"51baa8c1"},
},
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from A to B",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
Parents: []string{"51baa8c1"},
},
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from master to A",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
Parents: []string{"51baa8c1"},
},
{
Sha: "f4ddf2f0d4be4ccc7efa",
Hash: "f4ddf2f0d4be4ccc7efa",
Name: "checkout: moving from A to master",
Status: models.StatusReflog,
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),
lastReflogCommit: &models.Commit{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from B to A",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
@@ -101,7 +102,7 @@ func TestGetReflogCommits(t *testing.T) {
},
expectedCommits: []*models.Commit{
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from A to B",
Status: models.StatusReflog,
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),
lastReflogCommit: &models.Commit{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from B to A",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
@@ -126,7 +127,32 @@ func TestGetReflogCommits(t *testing.T) {
filterPath: "path",
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",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
@@ -150,14 +176,13 @@ func TestGetReflogCommits(t *testing.T) {
}
for _, scenario := range scenarios {
scenario := scenario
t.Run(scenario.testName, func(t *testing.T) {
builder := &ReflogCommitLoader{
Common: utils.NewDummyCommon(),
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.expectedError, err)
t.Logf("actual commits: \n%s", litter.Sdump(commits))

View File

@@ -2,6 +2,7 @@ package git_commands
import (
"fmt"
"strings"
"github.com/jesseduffield/gocui"
)
@@ -48,12 +49,21 @@ func (self *RemoteCommands) UpdateRemoteUrl(remoteName string, updatedUrl string
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").
Arg(remoteName, "--delete", branchName).
Arg(remoteName, "--delete").
Arg(branchNames...).
ToArgv()
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
cmdArgs := NewGitCmd("push").
Arg(remoteName, "--delete", tagName).
ToArgv()
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}
// CheckRemoteBranchExists Returns remote branch
@@ -66,3 +76,14 @@ func (self *RemoteCommands) CheckRemoteBranchExists(branchName string) bool {
return err == nil
}
// Resolve what might be a aliased URL into a full URL
// SEE: `man -P 'less +/--get-url +n' git-ls-remote`
func (self *RemoteCommands) GetRemoteURL(remoteName string) (string, error) {
cmdArgs := NewGitCmd("ls-remote").
Arg("--get-url", remoteName).
ToArgv()
url, err := self.cmd.New(cmdArgs).RunWithOutput()
return strings.TrimSpace(url), err
}

View File

@@ -2,14 +2,16 @@ package git_commands
import (
"fmt"
"regexp"
"strings"
"sync"
"github.com/jesseduffield/generics/slices"
gogit "github.com/jesseduffield/go-git/v5"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"golang.org/x/exp/slices"
)
type RemoteLoader struct {
@@ -31,29 +33,31 @@ func NewRemoteLoader(
}
func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) {
cmdArgs := NewGitCmd("branch").Arg("-r").ToArgv()
remoteBranchesStr, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err != nil {
return nil, err
}
wg := sync.WaitGroup{}
wg.Add(1)
var remoteBranchesByRemoteName map[string][]*models.RemoteBranch
var remoteBranchesErr error
go utils.Safe(func() {
defer wg.Done()
remoteBranchesByRemoteName, remoteBranchesErr = self.getRemoteBranchesByRemoteName()
})
goGitRemotes, err := self.getGoGitRemotes()
if err != nil {
return nil, err
}
// first step is to get our remotes from go-git
remotes := slices.Map(goGitRemotes, func(goGitRemote *gogit.Remote) *models.Remote {
remoteName := goGitRemote.Config().Name
wg.Wait()
re := regexp.MustCompile(fmt.Sprintf(`(?m)^\s*%s\/([\S]+)`, regexp.QuoteMeta(remoteName)))
matches := re.FindAllStringSubmatch(remoteBranchesStr, -1)
branches := slices.Map(matches, func(match []string) *models.RemoteBranch {
return &models.RemoteBranch{
Name: match[1],
RemoteName: remoteName,
}
})
if remoteBranchesErr != nil {
return nil, remoteBranchesErr
}
remotes := lo.Map(goGitRemotes, func(goGitRemote *gogit.Remote, _ int) *models.Remote {
remoteName := goGitRemote.Config().Name
branches := remoteBranchesByRemoteName[remoteName]
return &models.Remote{
Name: goGitRemote.Config().Name,
@@ -76,3 +80,51 @@ func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) {
return remotes, nil
}
func (self *RemoteLoader) getRemoteBranchesByRemoteName() (map[string][]*models.RemoteBranch, error) {
remoteBranchesByRemoteName := make(map[string][]*models.RemoteBranch)
var sortOrder string
switch strings.ToLower(self.AppState.RemoteBranchSortOrder) {
case "alphabetical":
sortOrder = "refname"
case "date":
sortOrder = "-committerdate"
default:
sortOrder = "refname"
}
cmdArgs := NewGitCmd("for-each-ref").
Arg(fmt.Sprintf("--sort=%s", sortOrder)).
Arg("--format=%(refname:short)").
Arg("refs/remotes").
ToArgv()
err := self.cmd.New(cmdArgs).DontLog().RunAndProcessLines(func(line string) (bool, error) {
line = strings.TrimSpace(line)
split := strings.SplitN(line, "/", 2)
if len(split) != 2 {
return false, nil
}
remoteName := split[0]
name := split[1]
_, ok := remoteBranchesByRemoteName[remoteName]
if !ok {
remoteBranchesByRemoteName[remoteName] = []*models.RemoteBranch{}
}
remoteBranchesByRemoteName[remoteName] = append(remoteBranchesByRemoteName[remoteName],
&models.RemoteBranch{
Name: name,
RemoteName: remoteName,
})
return false, nil
})
if err != nil {
return nil, err
}
return remoteBranchesByRemoteName, nil
}

View File

@@ -0,0 +1,187 @@
package git_commands
import (
ioFs "io/fs"
"os"
"path/filepath"
"strings"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero"
)
type RepoPaths struct {
worktreePath string
worktreeGitDirPath string
repoPath string
repoGitDirPath string
repoName string
isBareRepo bool
}
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
// Path to the current worktree. If we're in the main worktree, this will
// be the same as RepoPath()
func (self *RepoPaths) WorktreePath() string {
return self.worktreePath
}
// Path of the worktree's git dir.
// If we're in the main worktree, this will be the .git dir under the RepoPath().
// If we're in a linked worktree, it will be the directory pointed at by the worktree's .git file
func (self *RepoPaths) WorktreeGitDirPath() string {
return self.worktreeGitDirPath
}
// Path of the repo. If we're in a the main worktree, this will be the same as WorktreePath()
// If we're in a bare repo, it will be the parent folder of the bare repo
func (self *RepoPaths) RepoPath() string {
return self.repoPath
}
// path of the git-dir for the repo.
// If this is a bare repo, it will be the location of the bare repo
// If this is a non-bare repo, it will be the location of the .git dir in
// the main worktree.
func (self *RepoPaths) RepoGitDirPath() string {
return self.repoGitDirPath
}
// Name of the repo. Basename of the folder containing the repo.
func (self *RepoPaths) RepoName() string {
return self.repoName
}
func (self *RepoPaths) IsBareRepo() bool {
return self.isBareRepo
}
// Returns the repo paths for a typical repo
func MockRepoPaths(currentPath string) *RepoPaths {
return &RepoPaths{
worktreePath: currentPath,
worktreeGitDirPath: filepath.Join(currentPath, ".git"),
repoPath: currentPath,
repoGitDirPath: filepath.Join(currentPath, ".git"),
repoName: "lazygit",
isBareRepo: false,
}
}
func GetRepoPaths(
cmd oscommands.ICmdObjBuilder,
version *GitVersion,
) (*RepoPaths, error) {
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
return GetRepoPathsForDir(cwd, cmd, version)
}
func GetRepoPathsForDir(
dir string,
cmd oscommands.ICmdObjBuilder,
version *GitVersion,
) (*RepoPaths, error) {
gitDirOutput, err := callGitRevParseWithDir(cmd, version, dir, "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree")
if err != nil {
return nil, err
}
gitDirResults := strings.Split(utils.NormalizeLinefeeds(gitDirOutput), "\n")
worktreePath := gitDirResults[0]
worktreeGitDirPath := gitDirResults[1]
repoGitDirPath := gitDirResults[2]
if version.IsOlderThanVersion(&gitPathFormatVersion) {
repoGitDirPath, err = filepath.Abs(repoGitDirPath)
if err != nil {
return nil, err
}
}
isBareRepo := gitDirResults[3] == "true"
// If we're in a submodule, --show-superproject-working-tree will return
// a value, meaning gitDirResults will be length 5. In that case
// return the worktree path as the repoPath. Otherwise we're in a
// normal repo or a worktree so return the parent of the git common
// dir (repoGitDirPath)
isSubmodule := len(gitDirResults) == 5
var repoPath string
if isSubmodule {
repoPath = worktreePath
} else {
repoPath = filepath.Dir(repoGitDirPath)
}
repoName := filepath.Base(repoPath)
return &RepoPaths{
worktreePath: worktreePath,
worktreeGitDirPath: worktreeGitDirPath,
repoPath: repoPath,
repoGitDirPath: repoGitDirPath,
repoName: repoName,
isBareRepo: isBareRepo,
}, nil
}
func callGitRevParseWithDir(
cmd oscommands.ICmdObjBuilder,
version *GitVersion,
dir string,
gitRevArgs ...string,
) (string, error) {
gitRevParse := NewGitCmd("rev-parse").ArgIf(version.IsAtLeastVersion(&gitPathFormatVersion), "--path-format=absolute").Arg(gitRevArgs...)
if dir != "" {
gitRevParse.Dir(dir)
}
gitCmd := cmd.New(gitRevParse.ToArgv()).DontLog()
res, err := gitCmd.RunWithOutput()
if err != nil {
return "", errors.Errorf("'%s' failed: %v", gitCmd.ToString(), err)
}
return strings.TrimSpace(res), nil
}
// Returns the paths of linked worktrees
func linkedWortkreePaths(fs afero.Fs, repoGitDirPath string) []string {
result := []string{}
// For each directory in this path we're going to cat the `gitdir` file and append its contents to our result
// That file points us to the `.git` file in the worktree.
worktreeGitDirsPath := filepath.Join(repoGitDirPath, "worktrees")
// ensure the directory exists
_, err := fs.Stat(worktreeGitDirsPath)
if err != nil {
return result
}
_ = afero.Walk(fs, worktreeGitDirsPath, func(currPath string, info ioFs.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
return nil
}
gitDirPath := filepath.Join(currPath, "gitdir")
gitDirBytes, err := afero.ReadFile(fs, gitDirPath)
if err != nil {
// ignoring error
return nil
}
trimmedGitDir := strings.TrimSpace(string(gitDirBytes))
// removing the .git part
worktreeDir := filepath.Dir(trimmedGitDir)
result = append(result, worktreeDir)
return nil
})
return result
}

View File

@@ -0,0 +1,227 @@
package git_commands
import (
"fmt"
"runtime"
"strings"
"testing"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
)
type (
argFn func() []string
errFn func(getRevParseArgs argFn) error
)
type Scenario struct {
Name string
BeforeFunc func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn)
Path string
Expected *RepoPaths
Err errFn
}
func TestGetRepoPaths(t *testing.T) {
scenarios := []Scenario{
{
Name: "typical case",
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
// setup for main worktree
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
"/path/to/repo",
// --git-dir
"/path/to/repo/.git",
// --git-common-dir
"/path/to/repo/.git",
// --is-bare-repository
"false",
// --show-superproject-working-tree
})
runner.ExpectGitArgs(
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
strings.Join(mockOutput, "\n"),
nil)
},
Path: "/path/to/repo",
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",
worktreeGitDirPath: "/path/to/repo/.git",
repoPath: "/path/to/repo",
repoGitDirPath: "/path/to/repo/.git",
repoName: "repo",
isBareRepo: false,
}),
Err: nil,
},
{
Name: "bare repo",
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
// setup for main worktree
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,
},
{
Name: "submodule",
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
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
"/path/to/repo/submodule1",
// --git-dir
"/path/to/repo/.git/modules/submodule1",
// --git-common-dir
"/path/to/repo/.git/modules/submodule1",
// --is-bare-repository
"false",
// --show-superproject-working-tree
"/path/to/repo",
})
runner.ExpectGitArgs(
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
strings.Join(mockOutput, "\n"),
nil)
},
Path: "/path/to/repo/submodule1",
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",
worktreeGitDirPath: "/path/to/repo/.git/modules/submodule1",
repoPath: "/path/to/repo/submodule1",
repoGitDirPath: "/path/to/repo/.git/modules/submodule1",
repoName: "submodule1",
isBareRepo: false,
}),
Err: nil,
},
{
Name: "git rev-parse returns an error",
BeforeFunc: func(runner *oscommands.FakeCmdObjRunner, getRevParseArgs argFn) {
runner.ExpectGitArgs(
append(getRevParseArgs(), "--show-toplevel", "--absolute-git-dir", "--git-common-dir", "--is-bare-repository", "--show-superproject-working-tree"),
"",
errors.New("fatal: invalid gitfile format: /path/to/repo/worktree2/.git"))
},
Path: "/path/to/repo/worktree2",
Expected: nil,
Err: func(getRevParseArgs argFn) error {
args := strings.Join(getRevParseArgs(), " ")
return errors.New(
fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args),
)
},
},
}
for _, s := range scenarios {
t.Run(s.Name, func(t *testing.T) {
runner := oscommands.NewFakeRunner(t)
cmd := oscommands.NewDummyCmdObjBuilder(runner)
version, err := GetGitVersion(oscommands.NewDummyOSCommand())
if err != nil {
t.Fatal(err)
}
getRevParseArgs := func() []string {
args := []string{"rev-parse"}
if version.IsAtLeast(2, 31, 0) {
args = append(args, "--path-format=absolute")
}
return args
}
// prepare the filesystem for the scenario
s.BeforeFunc(runner, getRevParseArgs)
repoPaths, err := GetRepoPathsForDir("", cmd, version)
// check the error and the paths
if s.Err != nil {
scenarioErr := s.Err(getRevParseArgs)
assert.Error(t, err)
assert.EqualError(t, err, scenarioErr.Error())
} else {
assert.Nil(t, err)
assert.Equal(t, s.Expected, repoPaths)
}
})
}
}

View File

@@ -60,34 +60,36 @@ func (self *StashCommands) Push(message string) error {
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")
cmdArgs := NewGitCmd("stash").Arg("store").
ArgIf(trimmedMessage != "", "-m", trimmedMessage).
Arg(sha).
Arg(hash).
ToArgv()
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").
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
ToArgv()
sha, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
return strings.Trim(sha, "\r\n"), err
hash, _, err := self.cmd.New(cmdArgs).DontLog().RunWithOutputs()
return strings.Trim(hash, "\r\n"), err
}
func (self *StashCommands) ShowStashEntryCmdObj(index int, ignoreWhitespace bool) oscommands.ICmdObj {
func (self *StashCommands) ShowStashEntryCmdObj(index int) oscommands.ICmdObj {
cmdArgs := NewGitCmd("stash").Arg("show").
Arg("-p").
Arg("--stat").
Arg(fmt.Sprintf("--color=%s", self.UserConfig.Git.Paging.ColorArg)).
Arg(fmt.Sprintf("--unified=%d", self.UserConfig.Git.DiffContextSize)).
ArgIf(ignoreWhitespace, "--ignore-all-space").
Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)).
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
Arg(fmt.Sprintf("stash@{%d}", index)).
Dir(self.repoPaths.worktreePath).
ToArgv()
return self.cmd.New(cmdArgs).DontLog()
@@ -120,9 +122,22 @@ func (self *StashCommands) StashUnstagedChanges(message string) error {
return nil
}
// SaveStagedChanges stashes only the currently staged changes. This takes a few steps
// shoutouts to Joe on https://stackoverflow.com/questions/14759748/stashing-only-staged-changes-in-git-is-it-possible
// SaveStagedChanges stashes only the currently staged changes.
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
if err := self.cmd.New(
NewGitCmd("stash").Arg("--keep-index").ToArgv(),
@@ -178,7 +193,7 @@ func (self *StashCommands) StashIncludeUntrackedChanges(message string) error {
}
func (self *StashCommands) Rename(index int, message string) error {
sha, err := self.Sha(index)
hash, err := self.Hash(index)
if err != nil {
return err
}
@@ -187,7 +202,7 @@ func (self *StashCommands) Rename(index int, message string) error {
return err
}
err = self.Store(sha, message)
err = self.Store(hash, message)
if err != nil {
return err
}

View File

@@ -5,11 +5,11 @@ import (
"strconv"
"strings"
"github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
type StashLoader struct {
@@ -32,14 +32,14 @@ func (self *StashLoader) GetStashEntries(filterPath string) []*models.StashEntry
return self.getUnfilteredStashEntries()
}
cmdArgs := NewGitCmd("stash").Arg("list", "--name-only").ToArgv()
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--name-only", "--pretty=%ct|%gs").ToArgv()
rawString, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
if err != nil {
return self.getUnfilteredStashEntries()
}
stashEntries := []*models.StashEntry{}
var currentStashEntry *models.StashEntry
lines := utils.SplitLines(rawString)
lines := utils.SplitNul(rawString)
isAStash := func(line string) bool { return strings.HasPrefix(line, "stash@{") }
re := regexp.MustCompile(`stash@\{(\d+)\}`)
@@ -66,17 +66,32 @@ outer:
}
func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry {
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%gs").ToArgv()
cmdArgs := NewGitCmd("stash").Arg("list", "-z", "--pretty=%ct|%gs").ToArgv()
rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return slices.MapWithIndex(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
return lo.Map(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
return self.stashEntryFromLine(line, index)
})
}
func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry {
return &models.StashEntry{
model := &models.StashEntry{
Name: line,
Index: index,
}
tstr, msg, ok := strings.Cut(line, "|")
if !ok {
return model
}
t, err := strconv.ParseInt(tstr, 10, 64)
if err != nil {
return model
}
model.Name = msg
model.Recency = utils.UnixToTimeAgo(t)
return model
}

View File

@@ -22,14 +22,14 @@ func TestGetStashEntries(t *testing.T) {
"No stash entries found",
"",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%gs"}, "", nil),
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"}, "", nil),
[]*models.StashEntry{},
},
{
"Several stash entries found",
"",
oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%gs"},
ExpectGitArgs([]string{"stash", "list", "-z", "--pretty=%ct|%gs"},
"WIP on add-pkg-commands-test: 55c6af2 increase parallel build\x00WIP on master: bb86a3f update github template\x00",
nil,
),
@@ -47,7 +47,6 @@ func TestGetStashEntries(t *testing.T) {
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
cmd := oscommands.NewDummyCmdObjBuilder(s.runner)

View File

@@ -47,7 +47,7 @@ func TestStashSave(t *testing.T) {
func TestStashStore(t *testing.T) {
type scenario struct {
testName string
sha string
hash string
message string
expected []string
}
@@ -55,89 +55,105 @@ func TestStashStore(t *testing.T) {
scenarios := []scenario{
{
testName: "Non-empty message",
sha: "0123456789abcdef",
hash: "0123456789abcdef",
message: "New stash name",
expected: []string{"stash", "store", "-m", "New stash name", "0123456789abcdef"},
},
{
testName: "Empty message",
sha: "0123456789abcdef",
hash: "0123456789abcdef",
message: "",
expected: []string{"stash", "store", "0123456789abcdef"},
},
{
testName: "Space message",
sha: "0123456789abcdef",
hash: "0123456789abcdef",
message: " ",
expected: []string{"stash", "store", "0123456789abcdef"},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
runner := oscommands.NewFakeRunner(t).
ExpectGitArgs(s.expected, "", nil)
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()
})
}
}
func TestStashSha(t *testing.T) {
func TestStashHash(t *testing.T) {
runner := oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"rev-parse", "refs/stash@{5}"}, "14d94495194651adfd5f070590df566c11d28243\n", nil)
instance := buildStashCommands(commonDeps{runner: runner})
sha, err := instance.Sha(5)
hash, err := instance.Hash(5)
assert.NoError(t, err)
assert.Equal(t, "14d94495194651adfd5f070590df566c11d28243", sha)
assert.Equal(t, "14d94495194651adfd5f070590df566c11d28243", hash)
runner.CheckForMissingCalls()
}
func TestStashStashEntryCmdObj(t *testing.T) {
type scenario struct {
testName string
index int
contextSize int
ignoreWhitespace bool
expected []string
testName string
index int
contextSize uint64
similarityThreshold int
ignoreWhitespace bool
expected []string
}
scenarios := []scenario{
{
testName: "Default case",
index: 5,
contextSize: 3,
ignoreWhitespace: false,
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "stash@{5}"},
testName: "Default case",
index: 5,
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=50%", "stash@{5}"},
},
{
testName: "Show diff with custom context size",
index: 5,
contextSize: 77,
ignoreWhitespace: false,
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "stash@{5}"},
testName: "Show diff with custom context size",
index: 5,
contextSize: 77,
similarityThreshold: 50,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=77", "--find-renames=50%", "stash@{5}"},
},
{
testName: "Default case",
index: 5,
contextSize: 3,
ignoreWhitespace: true,
expected: []string{"git", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "stash@{5}"},
testName: "Show diff with custom similarity threshold",
index: 5,
contextSize: 3,
similarityThreshold: 33,
ignoreWhitespace: false,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--find-renames=33%", "stash@{5}"},
},
{
testName: "Default case",
index: 5,
contextSize: 3,
similarityThreshold: 50,
ignoreWhitespace: true,
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "stash@{5}"},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
userConfig := config.GetDefaultConfig()
userConfig.Git.DiffContextSize = s.contextSize
instance := buildStashCommands(commonDeps{userConfig: userConfig})
appState := &config.AppState{}
appState.IgnoreWhitespaceInDiffView = s.ignoreWhitespace
appState.DiffContextSize = s.contextSize
appState.RenameSimilarityThreshold = s.similarityThreshold
repoPaths := RepoPaths{
worktreePath: "/path/to/worktree",
}
instance := buildStashCommands(commonDeps{userConfig: userConfig, appState: appState, repoPaths: &repoPaths})
cmdStr := instance.ShowStashEntryCmdObj(s.index, s.ignoreWhitespace).Args()
cmdStr := instance.ShowStashEntryCmdObj(s.index).Args()
assert.Equal(t, s.expected, cmdStr)
})
}
@@ -148,8 +164,8 @@ func TestStashRename(t *testing.T) {
testName string
index int
message string
expectedShaCmd []string
shaResult string
expectedHashCmd []string
hashResult string
expectedDropCmd []string
expectedStoreCmd []string
}
@@ -159,8 +175,8 @@ func TestStashRename(t *testing.T) {
testName: "Default case",
index: 3,
message: "New message",
expectedShaCmd: []string{"rev-parse", "refs/stash@{3}"},
shaResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
expectedHashCmd: []string{"rev-parse", "refs/stash@{3}"},
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
expectedDropCmd: []string{"stash", "drop", "stash@{3}"},
expectedStoreCmd: []string{"stash", "store", "-m", "New message", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
},
@@ -168,18 +184,17 @@ func TestStashRename(t *testing.T) {
testName: "Empty message",
index: 4,
message: "",
expectedShaCmd: []string{"rev-parse", "refs/stash@{4}"},
shaResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
expectedHashCmd: []string{"rev-parse", "refs/stash@{4}"},
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
expectedDropCmd: []string{"stash", "drop", "stash@{4}"},
expectedStoreCmd: []string{"stash", "store", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
},
}
for _, s := range scenarios {
s := s
t.Run(s.testName, func(t *testing.T) {
runner := oscommands.NewFakeRunner(t).
ExpectGitArgs(s.expectedShaCmd, s.shaResult, nil).
ExpectGitArgs(s.expectedHashCmd, s.hashResult, nil).
ExpectGitArgs(s.expectedDropCmd, "", nil).
ExpectGitArgs(s.expectedStoreCmd, "", nil)
instance := buildStashCommands(commonDeps{runner: runner})

Some files were not shown because too many files have changed in this diff Show More