Compare commits

...

99 Commits

Author SHA1 Message Date
Luka Markušić
d8cffa314e Check for skipping pre-commit hooks in more situations 2024-04-27 08:48:21 +02:00
Luka Markušić
4ec41c4414 Add integration tests for skipping pre-commit hooks 2024-04-27 08:47:54 +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
212 changed files with 3182 additions and 11594 deletions

View File

@@ -15,14 +15,14 @@ jobs:
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

3
.gitignore vendored
View File

@@ -6,9 +6,6 @@
# Hidden
.*
# TODO
TODO.*
# Notes
*.notes

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@ If you want to change the config directory:
JSON schema is available for `config.yml` so that IntelliSense in Visual Studio Code (completion and error checking) is automatically enabled when the [YAML Red Hat][yaml] extension is installed. However, note that automatic schema detection only works if your config file is in one of the standard paths mentioned above. If you override the path to the file, you can still make IntelliSense work by adding
```yaml
# yaml-language-server: $schema=https://json.schemastore.org/lazygit.json
# yaml-language-server: $schema=https://raw.githubusercontent.com/jesseduffield/lazygit/master/schema/config.json
```
to the top of your config file or via [Visual Studio Code settings.json config][settings].
@@ -87,6 +87,10 @@ gui:
animateExplosion: true # shows an explosion animation when nuking the working tree
portraitMode: 'auto' # one of 'auto' | 'never' | 'always'
filterMode: 'substring' # one of 'substring' | 'fuzzy'; see 'Filtering' section below
spinner:
frames: ['|', '/', '-', '\\']
rate: 50 # spinner rate in milliseconds
statusPanelView: 'dashboard' # one of 'dashboard' | 'allBranchesLog'
git:
paging:
colorArg: always

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}}"
@@ -305,7 +305,7 @@ 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.
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.Hash}}` and `{{.SelectedLocalBranch.Name}}`. In the future we will likely introduce a tighter interface that exposes a limited set of fields for each model.
## Keybinding collisions

View File

@@ -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()`.

View File

@@ -76,7 +76,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit SHA to clipboard | |
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` 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. |
@@ -245,7 +245,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit SHA to clipboard | |
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |
@@ -313,7 +313,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Copy commit SHA to clipboard | |
| `` <c-o> `` | Copy commit hash to clipboard | |
| `` <space> `` | Checkout | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |

View File

@@ -66,7 +66,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
| `` <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 `` | ブラウザでコミットを開く | |
@@ -93,7 +93,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
| `` <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. |
@@ -343,7 +343,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | コミットのSHAをクリップボードにコピー | |
| `` <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 `` | ブラウザでコミットを開く | |

View File

@@ -53,7 +53,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
| `` <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 `` | 브라우저에서 커밋 열기 | |
@@ -83,7 +83,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
| `` <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 `` | 브라우저에서 커밋 열기 | |
@@ -256,7 +256,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 커밋 SHA를 클립보드에 복사 | |
| `` <c-o> `` | 커밋 해시를 클립보드에 복사 | |
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` b `` | Bisect 옵션 보기 | |
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |

View File

@@ -139,7 +139,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` 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. |
@@ -223,7 +223,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |
@@ -313,7 +313,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopieer commit SHA naar klembord | |
| `` <c-o> `` | Kopieer commit hash naar klembord | |
| `` <space> `` | Uitchecken | Checkout the selected commit as a detached HEAD. |
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
| `` o `` | Open commit in browser | |

View File

@@ -53,7 +53,7 @@ _Legenda: `<c-b>` oznacza ctrl+b, `<a-b>` oznacza alt+b, `B` oznacza shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj SHA commita do schowka | |
| `` <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. |
@@ -255,7 +255,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj SHA commita do schowka | |
| `` <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 | |
@@ -295,7 +295,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Kopiuj SHA commita do schowka | |
| `` <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 | |

View File

@@ -123,7 +123,7 @@ _Связки клавиш_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
| `` <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 `` | Открыть коммит в браузере | |
@@ -140,7 +140,7 @@ _Связки клавиш_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
| `` <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. |
@@ -219,7 +219,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | Скопировать SHA коммита в буфер обмена | |
| `` <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 `` | Открыть коммит в браузере | |

View File

@@ -53,7 +53,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <space> `` | 检出 | 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 `` | 在浏览器中打开提交 | |
@@ -106,7 +106,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <space> `` | 检出 | 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 `` | 在浏览器中打开提交 | |
@@ -137,7 +137,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 将提交的 SHA 复制到剪贴板 | |
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` b `` | 查看二分查找选项 | |
| `` s `` | 压缩 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |

View File

@@ -121,7 +121,7 @@ _說明`<c-b>` 表示 CtrlB、`<a-b>` 表示 AltB`B`表示 ShiftB
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
| `` <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 `` | 在瀏覽器中開啟提交 | |
@@ -162,7 +162,7 @@ _說明`<c-b>` 表示 CtrlB、`<a-b>` 表示 AltB`B`表示 ShiftB
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
| `` <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. |
@@ -236,7 +236,7 @@ If you would instead like to start an interactive rebase from the selected commi
| Key | Action | Info |
|-----|--------|-------------|
| `` <c-o> `` | 複製提交 SHA 到剪貼簿 | |
| `` <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 `` | 在瀏覽器中開啟提交 | |

11
go.mod
View File

@@ -8,7 +8,6 @@ require (
github.com/aybabtme/humanlog v0.4.1
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/gdamore/tcell/v2 v2.7.4
github.com/go-errors/errors v1.5.1
github.com/gookit/color v1.4.2
@@ -16,11 +15,10 @@ require (
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.20240309085756-86e0d5a312de
github.com/jesseduffield/gocui v0.3.1-0.20240418080333-8cd33929c513
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
github.com/jesseduffield/yaml v2.1.0+incompatible
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/karimkhaleel/jsonschema v0.0.0-20231001195015-d933f0d94ea3
github.com/kyokomi/emoji/v2 v2.2.8
@@ -35,6 +33,7 @@ require (
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/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
@@ -48,7 +47,7 @@ require (
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
@@ -74,8 +73,8 @@ require (
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

21
go.sum
View File

@@ -84,11 +84,10 @@ github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/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/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=
github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
@@ -187,16 +186,14 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/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.20240309085756-86e0d5a312de h1:2ww1SWgakihE8hFxZ7L3agVeGpA6qwW5vdnhFUXKMQo=
github.com/jesseduffield/gocui v0.3.1-0.20240309085756-86e0d5a312de/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
github.com/jesseduffield/gocui v0.3.1-0.20240418080333-8cd33929c513 h1:Y1bw5iItrsDCumATc/rklIJ/6K+68ieiWZJedhrNuXo=
github.com/jesseduffield/gocui v0.3.1-0.20240418080333-8cd33929c513/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5/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/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE=
github.com/jesseduffield/yaml v2.1.0+incompatible/go.mod h1:w0xGhOSIJCGYYW+hnFPTutCy5aACpkcwbmORt5axGqk=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/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=
@@ -282,6 +279,8 @@ 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/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -471,14 +470,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
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=

View File

@@ -8,11 +8,11 @@ import (
"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/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
// Sometimes lazygit will be invoked in daemon mode from a parent lazygit process.
@@ -33,12 +33,14 @@ const (
DaemonKindUnknown DaemonKind = iota
DaemonKindExitImmediately
DaemonKindRemoveUpdateRefsForCopiedBranch
DaemonKindCherryPick
DaemonKindMoveTodosUp
DaemonKindMoveTodosDown
DaemonKindInsertBreak
DaemonKindChangeTodoActions
DaemonKindMoveFixupCommitDown
DaemonKindWriteRebaseTodo
)
const (
@@ -52,13 +54,15 @@ 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],
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
DaemonKindExitImmediately: deserializeInstruction[*ExitImmediatelyInstruction],
DaemonKindRemoveUpdateRefsForCopiedBranch: deserializeInstruction[*RemoveUpdateRefsForCopiedBranchInstruction],
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
DaemonKindInsertBreak: deserializeInstruction[*InsertBreakInstruction],
DaemonKindWriteRebaseTodo: deserializeInstruction[*WriteRebaseTodoInstruction],
}
return mapping[getDaemonKind()](jsonData)
@@ -155,6 +159,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
}
@@ -210,7 +234,7 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
return handleInteractiveRebase(common, func(path string) error {
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
return utils.TodoChange{
Sha: c.Sha,
Hash: c.Hash,
OldAction: todo.Pick,
NewAction: c.NewAction,
}
@@ -220,18 +244,18 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
})
}
// Takes the sha of some commit, and the sha of a fixup commit that was created
// Takes the hash of some commit, and the hash of a fixup commit that was created
// at the end of the branch, then moves the fixup commit down to right after the
// original commit, changing its type to "fixup"
type MoveFixupCommitDownInstruction struct {
OriginalSha string
FixupSha string
OriginalHash string
FixupHash string
}
func NewMoveFixupCommitDownInstruction(originalSha string, fixupSha string) Instruction {
func NewMoveFixupCommitDownInstruction(originalHash string, fixupHash string) Instruction {
return &MoveFixupCommitDownInstruction{
OriginalSha: originalSha,
FixupSha: fixupSha,
OriginalHash: originalHash,
FixupHash: fixupHash,
}
}
@@ -245,17 +269,17 @@ 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, getCommentChar())
})
}
type MoveTodosUpInstruction struct {
Shas []string
Hashes []string
}
func NewMoveTodosUpInstruction(shas []string) Instruction {
func NewMoveTodosUpInstruction(hashes []string) Instruction {
return &MoveTodosUpInstruction{
Shas: shas,
Hashes: hashes,
}
}
@@ -268,9 +292,9 @@ func (self *MoveTodosUpInstruction) SerializedInstructions() string {
}
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
return utils.Todo{
Sha: sha,
Hash: hash,
Action: todo.Pick,
}
})
@@ -281,12 +305,12 @@ func (self *MoveTodosUpInstruction) run(common *common.Common) error {
}
type MoveTodosDownInstruction struct {
Shas []string
Hashes []string
}
func NewMoveTodosDownInstruction(shas []string) Instruction {
func NewMoveTodosDownInstruction(hashes []string) Instruction {
return &MoveTodosDownInstruction{
Shas: shas,
Hashes: hashes,
}
}
@@ -299,9 +323,9 @@ func (self *MoveTodosDownInstruction) SerializedInstructions() string {
}
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
todosToMove := lo.Map(self.Shas, func(sha string, _ int) utils.Todo {
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
return utils.Todo{
Sha: sha,
Hash: hash,
Action: todo.Pick,
}
})
@@ -330,3 +354,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/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,7 +22,7 @@ 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"
}
}
@@ -34,7 +35,7 @@ func TodoLinesToString(todoLines []TodoLine) string {
}
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

@@ -263,7 +263,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

View File

@@ -76,7 +76,7 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
return info
}
sha := strings.TrimSpace(string(fileContent))
hash := strings.TrimSpace(string(fileContent))
if name == info.newTerm {
status = BisectStatusNew
@@ -86,7 +86,7 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
status = BisectStatusSkipped
}
info.statusMap[sha] = status
info.statusMap[hash] = status
}
currentContent, err := os.ReadFile(filepath.Join(gitDir, "BISECT_EXPECTED_REV"))
@@ -94,8 +94,8 @@ func (self *BisectCommands) GetInfoForGitDir(gitDir string) *BisectInfo {
self.Log.Infof("error getting git bisect info: %s", err.Error())
return info
}
currentSha := strings.TrimSpace(string(currentContent))
info.current = currentSha
currentHash := strings.TrimSpace(string(currentContent))
info.current = currentHash
return info
}
@@ -135,7 +135,7 @@ func (self *BisectCommands) StartWithTerms(oldTerm string, newTerm string) error
}
// tells us whether we've found our problem commit(s). We return a string slice of
// 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()
@@ -143,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
}
@@ -153,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
@@ -185,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

@@ -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,7 +93,7 @@ func (self *BisectInfo) Bisecting() bool {
return false
}
if self.GetNewSha() == "" {
if self.GetNewHash() == "" {
return false
}

View File

@@ -65,10 +65,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

View File

@@ -22,7 +22,13 @@ func NewCommitCommands(gitCommon *GitCommon) *CommitCommands {
// ResetAuthor resets the author of the topmost commit
func (self *CommitCommands) ResetAuthor() error {
message, err := self.GetCommitMessage("HEAD")
if err != nil {
return err
}
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
Arg("--allow-empty", "--only", "--no-edit", "--amend", "--reset-author").
ToArgv()
@@ -31,7 +37,14 @@ func (self *CommitCommands) ResetAuthor() error {
// Sets the commit's author to the supplied value. Value is expected to be of the form 'Name <Email>'
func (self *CommitCommands) SetAuthor(value string) error {
message, err := self.GetCommitMessage("HEAD")
if err != nil {
return err
}
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
Arg("--allow-empty", "--only", "--no-edit", "--amend", "--author="+value).
ToArgv()
@@ -39,15 +52,18 @@ func (self *CommitCommands) SetAuthor(value string) error {
}
// Add a commit's coauthor using Github/Gitlab Co-authored-by metadata. Value is expected to be of the form 'Name <Email>'
func (self *CommitCommands) AddCoAuthor(sha string, author string) error {
message, err := self.GetCommitMessage(sha)
func (self *CommitCommands) AddCoAuthor(hash string, author string) error {
message, err := self.GetCommitMessage(hash)
if err != nil {
return err
}
message = AddCoAuthorToMessage(message, author)
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
Arg("--allow-empty", "--amend", "--only", "-m", message).
ToArgv()
@@ -74,8 +90,8 @@ func AddCoAuthorToDescription(description string, author string) string {
}
// 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
@@ -100,11 +116,15 @@ func (self *CommitCommands) CommitCmdObj(summary string, description string) osc
}
func (self *CommitCommands) RewordLastCommitInEditorCmdObj() oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").Arg("--allow-empty", "--amend", "--only").ToArgv())
return self.cmd.New(NewGitCmd("commit").
// TODO: how to decide if we should add --no-verify if we're using the editor?
Arg("--allow-empty", "--amend", "--only").ToArgv())
}
func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
// TODO: how to decide if we should add --no-verify if we're using the editor?
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
}
@@ -120,7 +140,10 @@ func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile s
func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
messageArgs := self.commitMessageArgs(summary, description)
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
Arg("--allow-empty", "--amend", "--only").
Arg(messageArgs...).
ToArgv()
@@ -155,26 +178,28 @@ func (self *CommitCommands) signoffFlag() string {
}
}
func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) {
func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) {
cmdArgs := NewGitCmd("log").
Arg("--format=%B", "--max-count=1", commitSha).
Arg("--format=%B", "--max-count=1", commitHash).
Config("log.showsignature=false").
ToArgv()
message, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
return strings.ReplaceAll(strings.TrimSpace(message), "\r\n", "\n"), err
}
func (self *CommitCommands) GetCommitSubject(commitSha string) (string, error) {
func (self *CommitCommands) GetCommitSubject(commitHash string) (string, error) {
cmdArgs := NewGitCmd("log").
Arg("--format=%s", "--max-count=1", commitSha).
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(commitSha string) (string, error) {
cmdArgs := NewGitCmd("show").Arg("--no-color", commitSha).ToArgv()
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
@@ -185,9 +210,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()
@@ -204,14 +229,14 @@ 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()
@@ -222,19 +247,19 @@ func (self *CommitCommands) GetCommitMessagesFirstLine(shas []string) (string, e
// 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) GetShasAndCommitMessagesFirstLine(shas []string) (string, error) {
func (self *CommitCommands) GetHashesAndCommitMessagesFirstLine(hashes []string) (string, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--pretty=format:%h %s").
Arg(shas...).
Arg(hashes...).
ToArgv()
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
}
func (self *CommitCommands) GetCommitsOneline(shas []string) (string, error) {
func (self *CommitCommands) GetCommitsOneline(hashes []string) (string, error) {
cmdArgs := NewGitCmd("show").
Arg("--no-patch", "--oneline").
Arg(shas...).
Arg(hashes...).
ToArgv()
return self.cmd.New(cmdArgs).DontLog().RunWithOutput()
@@ -246,14 +271,22 @@ func (self *CommitCommands) AmendHead() error {
}
func (self *CommitCommands) AmendHeadCmdObj() oscommands.ICmdObj {
message, err := self.GetCommitMessage("HEAD")
if err != nil {
// TODO: what to do here? we can't return err
// return err
}
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify").
Arg("--amend", "--no-edit", "--allow-empty").
ToArgv()
return self.cmd.New(cmdArgs)
}
func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands.ICmdObj {
func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommands.ICmdObj {
contextSize := self.AppState.DiffContextSize
extDiffCmd := self.UserConfig.Git.Paging.ExternalDiffCommand
@@ -267,7 +300,7 @@ func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands
Arg("--stat").
Arg("--decorate").
Arg("-p").
Arg(sha).
Arg(hash).
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
ArgIf(filterPath != "", "--", filterPath).
Dir(self.repoPaths.worktreePath).
@@ -276,23 +309,23 @@ func (self *CommitCommands) ShowCmdObj(sha string, filterPath string) oscommands
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()
}

View File

@@ -11,13 +11,13 @@ import (
"strings"
"sync"
"github.com/fsmiamoto/git-todo-parser/todo"
"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:
@@ -129,7 +129,7 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
}
for _, commit := range commits {
if commit.Sha == firstPushedCommit {
if commit.Hash == firstPushedCommit {
passedFirstPushedCommit = true
}
if commit.Status != models.StatusRebasing {
@@ -198,14 +198,14 @@ 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, 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]
@@ -241,7 +241,7 @@ func (self *CommitLoader) extractCommitFromLine(line string, showDivergence bool
}
return &models.Commit{
Sha: sha,
Hash: hash,
Name: message,
Tags: tags,
ExtraInfo: extraInfo,
@@ -260,8 +260,8 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode
return nil, nil
}
commitShas := lo.FilterMap(commits, func(commit *models.Commit, _ int) (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
@@ -270,14 +270,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, false)
fullCommits[commit.Sha] = commit
fullCommits[commit.Hash] = commit
return false, nil
})
if err != nil {
@@ -285,23 +285,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)
@@ -337,9 +337,9 @@ func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) []*mod
// 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,
@@ -354,7 +354,7 @@ func (self *CommitLoader) getRebasingCommits(rebaseMode enums.RebaseMode) []*mod
continue
}
commits = utils.Prepend(commits, &models.Commit{
Sha: t.Commit,
Hash: t.Commit,
Name: t.Msg,
Status: models.StatusRebasing,
Action: t.Command,
@@ -458,8 +458,8 @@ func setCommitMergedStatuses(ancestor string, commits []*models.Commit) {
passedAncestor := false
for i, commit := range commits {
// some commits aren't really commits and don't have sha's, such as the update-ref todo
if commit.Sha != "" && 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 {
@@ -559,7 +559,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(

View File

@@ -5,13 +5,13 @@ import (
"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"
)
@@ -86,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,
@@ -100,7 +100,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
Hash: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
Name: "fix logging",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -114,7 +114,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
Hash: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
Name: "refactor",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -128,7 +128,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "d8084cd558925eb7c9c38afeed5725c21653ab90",
Hash: "d8084cd558925eb7c9c38afeed5725c21653ab90",
Name: "WIP",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -142,7 +142,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
Hash: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
Name: "WIP",
Status: models.StatusPushed,
Action: models.ActionNone,
@@ -156,7 +156,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
Hash: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
Name: "WIP",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -170,7 +170,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
Hash: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
Name: "WIP",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -184,7 +184,7 @@ func TestGetCommits(t *testing.T) {
},
},
{
Sha: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
Hash: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
Name: "refactoring the config struct",
Status: models.StatusMerged,
Action: models.ActionNone,
@@ -221,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,
@@ -260,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,
@@ -339,14 +339,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)",
@@ -362,7 +362,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
{
testName: "last command was 'break'",
@@ -371,7 +371,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
{Command: todo.Break},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "last command was 'exec'",
@@ -383,7 +383,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "last command was 'reword'",
@@ -392,7 +392,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
{Command: todo.Reword},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "'pick' was rescheduled",
@@ -409,7 +409,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "'pick' was rescheduled, buggy git version",
@@ -434,7 +434,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "",
expectedHash: "",
},
{
testName: "conflicting 'pick' after 'exec'",
@@ -459,7 +459,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
{
testName: "'edit' with amend file",
@@ -471,7 +471,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: true,
expectedSha: "",
expectedHash: "",
},
{
testName: "'edit' without amend file",
@@ -483,7 +483,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
},
},
amendFileExists: false,
expectedSha: "fa1afe1",
expectedHash: "fa1afe1",
},
}
for _, scenario := range scenarios {
@@ -503,8 +503,8 @@ 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)
})
}
}
@@ -521,29 +521,29 @@ func TestCommitLoader_setCommitMergedStatuses(t *testing.T) {
{
testName: "basic",
commits: []*models.Commit{
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Sha: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusPushed},
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
{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{
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Sha: "67890", Name: "2", Action: models.ActionNone, Status: models.StatusMerged},
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusMerged},
{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{
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Sha: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
{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{
{Sha: "12345", Name: "1", Action: models.ActionNone, Status: models.StatusUnpushed},
{Sha: "", Name: "", Action: todo.UpdateRef, Status: models.StatusNone},
{Sha: "abcde", Name: "3", Action: models.ActionNone, Status: models.StatusPushed},
{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},
},
},
}

View File

@@ -153,7 +153,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)
}
@@ -161,7 +161,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) {
@@ -174,7 +174,7 @@ func TestCommitCreateFixupCommit(t *testing.T) {
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()
})
}
@@ -337,7 +337,7 @@ func TestGetCommitMsg(t *testing.T) {
s := s
t.Run(s.testName, func(t *testing.T) {
instance := buildCommitCommands(commonDeps{
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
runner: oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1", "deadbeef"}, s.input, nil),
})
output, err := instance.GetCommitMessage("deadbeef")
@@ -358,14 +358,14 @@ func TestGetCommitMessageFromHistory(t *testing.T) {
scenarios := []scenario{
{
"Empty message",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"log", "--format=%B", "--max-count=1"}, "", nil),
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "", nil).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1"}, "", nil),
func(output string, err error) {
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{"log", "--format=%B", "--max-count=1", "sha3"}, `use generics to DRY up context code`, nil),
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"log", "-1", "--skip=2", "--pretty=%H"}, "hash3 \n", nil).ExpectGitArgs([]string{"-c", "log.showsignature=false", "log", "--format=%B", "--max-count=1", "hash3"}, `use generics to DRY up context code`, nil),
func(output string, err error) {
assert.NoError(t, err)
assert.Equal(t, "use generics to DRY up context code", output)

View File

@@ -4,12 +4,12 @@ import (
"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/stefanhaller/git-todo-parser/todo"
)
type PatchCommands struct {
@@ -157,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()
@@ -219,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
}
}
@@ -324,7 +324,7 @@ func (self *PatchCommands) diffHeadAgainstCommit(commit *models.Commit) (string,
cmdArgs := NewGitCmd("diff").
Config("diff.noprefix=false").
Arg("--no-ext-diff").
Arg("HEAD.." + commit.Sha).
Arg("HEAD.." + commit.Hash).
ToArgv()
return self.cmd.New(cmdArgs).RunWithOutput()

View File

@@ -5,13 +5,13 @@ import (
"path/filepath"
"strings"
"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/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
type RebaseCommands struct {
@@ -56,14 +56,14 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, su
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
}
@@ -81,7 +81,7 @@ func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, index int,
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, index int, value string) error {
return self.GenericAmend(commits, index, func() error {
return self.commit.AddCoAuthor(commits[index].Sha, value)
return self.commit.AddCoAuthor(commits[index].Hash, value)
})
}
@@ -106,29 +106,29 @@ func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f
}
func (self *RebaseCommands) MoveCommitsDown(commits []*models.Commit, startIdx int, endIdx int) error {
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+2)
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+2)
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Sha
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Hash
})
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
instruction: daemon.NewMoveTodosDownInstruction(shas),
baseHashOrRoot: baseHashOrRoot,
instruction: daemon.NewMoveTodosDownInstruction(hashes),
overrideEditor: true,
}).Run()
}
func (self *RebaseCommands) MoveCommitsUp(commits []*models.Commit, startIdx int, endIdx int) error {
baseShaOrRoot := getBaseShaOrRoot(commits, endIdx+1)
baseHashOrRoot := getBaseHashOrRoot(commits, endIdx+1)
shas := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Sha
hashes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) string {
return commit.Hash
})
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
instruction: daemon.NewMoveTodosUpInstruction(shas),
baseHashOrRoot: baseHashOrRoot,
instruction: daemon.NewMoveTodosUpInstruction(hashes),
overrideEditor: true,
}).Run()
}
@@ -139,11 +139,11 @@ func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx
baseIndex++
}
baseShaOrRoot := getBaseShaOrRoot(commits, baseIndex)
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
changes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) daemon.ChangeTodoAction {
return daemon.ChangeTodoAction{
Sha: commit.Sha,
Hash: commit.Hash,
NewAction: action,
}
})
@@ -151,7 +151,7 @@ func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx
self.os.LogCommand(logTodoChanges(changes), false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseShaOrRoot,
baseHashOrRoot: baseHashOrRoot,
overrideEditor: true,
instruction: daemon.NewChangeTodoActionsInstruction(changes),
}).Run()
@@ -166,8 +166,8 @@ func (self *RebaseCommands) EditRebase(branchRef string) error {
)
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: branchRef,
instruction: daemon.NewInsertBreakInstruction(),
baseHashOrRoot: branchRef,
instruction: daemon.NewInsertBreakInstruction(),
}).Run()
}
@@ -181,21 +181,21 @@ func (self *RebaseCommands) EditRebaseFromBaseCommit(targetBranchName string, ba
)
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: baseCommit,
onto: targetBranchName,
instruction: daemon.NewInsertBreakInstruction(),
baseHashOrRoot: baseCommit,
onto: targetBranchName,
instruction: daemon.NewInsertBreakInstruction(),
}).Run()
}
func logTodoChanges(changes []daemon.ChangeTodoAction) string {
changeTodoStr := strings.Join(lo.Map(changes, func(c daemon.ChangeTodoAction, _ int) string {
return fmt.Sprintf("%s:%s", c.Sha, c.NewAction)
return fmt.Sprintf("%s:%s", c.Hash, c.NewAction)
}), "\n")
return fmt.Sprintf("Changing TODO actions:\n%s", changeTodoStr)
}
type PrepareInteractiveRebaseCommandOpts struct {
baseShaOrRoot string
baseHashOrRoot string
onto string
instruction daemon.Instruction
overrideEditor bool
@@ -204,7 +204,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()
@@ -216,7 +216,7 @@ func (self *RebaseCommands) PrepareInteractiveRebaseCommand(opts PrepareInteract
Arg("--no-autosquash").
ArgIf(self.version.IsAtLeast(2, 22, 0), "--rebase-merges").
ArgIf(opts.onto != "", "--onto", opts.onto).
Arg(opts.baseShaOrRoot).
Arg(opts.baseHashOrRoot).
ToArgv()
debug := "FALSE"
@@ -233,7 +233,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(
@@ -250,25 +250,55 @@ 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()
}
// 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
// Get the hash of the commit we just created
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
fixupSha, err := self.cmd.New(cmdArgs).RunWithOutput()
fixupHash, err := self.cmd.New(cmdArgs).RunWithOutput()
if err != nil {
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),
}).Run()
}
@@ -276,7 +306,7 @@ func todoFromCommit(commit *models.Commit) utils.Todo {
if commit.Action == todo.UpdateRef {
return utils.Todo{Ref: commit.Name, Action: commit.Action}
} else {
return utils.Todo{Sha: commit.Sha, Action: commit.Action}
return utils.Todo{Hash: commit.Hash, Action: commit.Action}
}
}
@@ -284,7 +314,7 @@ func todoFromCommit(commit *models.Commit) utils.Todo {
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{
Sha: commit.Sha,
Hash: commit.Hash,
OldAction: commit.Action,
NewAction: action,
}
@@ -302,11 +332,16 @@ func (self *RebaseCommands) DeleteUpdateRefTodos(commits []*models.Commit) error
return todoFromCommit(commit)
})
return utils.DeleteTodos(
todosFileContent, err := utils.DeleteTodos(
filepath.Join(self.repoPaths.WorktreeGitDirPath(), "rebase-merge/git-rebase-todo"),
todosToDelete,
self.config.GetCoreCommentChar(),
)
if err != nil {
return err
}
return self.GitRebaseEditTodo(todosFileContent)
}
func (self *RebaseCommands) MoveTodosDown(commits []*models.Commit) error {
@@ -329,13 +364,13 @@ func (self *RebaseCommands) MoveTodosUp(commits []*models.Commit) error {
// 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))
@@ -358,13 +393,13 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
}
changes := []daemon.ChangeTodoAction{{
Sha: commits[commitIndex].Sha,
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, commitIndex+1),
overrideEditor: true,
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
instruction: daemon.NewChangeTodoActionsInstruction(changes),
@@ -373,13 +408,13 @@ 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{
baseShaOrRoot: baseCommit,
onto: targetBranchName,
baseHashOrRoot: baseCommit,
onto: targetBranchName,
}).Run()
}
@@ -468,10 +503,10 @@ 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)
})
msg := utils.ResolvePlaceholderString(
self.Tr.Log.CherryPickCommits,
@@ -482,8 +517,8 @@ func (self *RebaseCommands) CherryPickCommits(commits []*models.Commit) error {
self.os.LogCommand(msg, false)
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
baseShaOrRoot: "HEAD",
instruction: daemon.NewCherryPickCommitsInstruction(commits),
baseHashOrRoot: "HEAD",
instruction: daemon.NewCherryPickCommitsInstruction(commits),
}).Run()
}
@@ -503,13 +538,13 @@ func (self *RebaseCommands) CherryPickCommitsDuringRebase(commits []*models.Comm
// 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

@@ -131,7 +131,7 @@ 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: []string{"test999.txt"},
runner: oscommands.NewFakeRunner(t),
@@ -143,8 +143,8 @@ 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: []string{"test999.txt"},

View File

@@ -45,7 +45,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
}
// note that the unix timestamp here is the timestamp of the COMMIT, not the reflog entry itself,
// 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 && self.sameReflogCommit(commit, lastReflogCommit) {
@@ -65,7 +65,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit
}
func (self *ReflogCommitLoader) sameReflogCommit(a *models.Commit, b *models.Commit) bool {
return a.Sha == b.Sha && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
return a.Hash == b.Hash && a.UnixTimestamp == b.UnixTimestamp && a.Name == b.Name
}
func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
@@ -83,7 +83,7 @@ func (self *ReflogCommitLoader) parseLine(line string) (*models.Commit, bool) {
}
return &models.Commit{
Sha: fields[0],
Hash: fields[0],
Name: fields[2],
UnixTimestamp: int64(unixTimestamp),
Status: models.StatusReflog,

View File

@@ -50,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,
@@ -94,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,
@@ -102,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,
@@ -118,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,
@@ -127,7 +127,7 @@ 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,
@@ -143,7 +143,7 @@ func TestGetReflogCommits(t *testing.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{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from B to A",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,
@@ -152,7 +152,7 @@ func TestGetReflogCommits(t *testing.T) {
filterAuthor: "John Doe <john@doe.com>",
expectedCommits: []*models.Commit{
{
Sha: "c3c4b66b64c97ffeecde",
Hash: "c3c4b66b64c97ffeecde",
Name: "checkout: moving from A to B",
Status: models.StatusReflog,
UnixTimestamp: 1643150483,

View File

@@ -60,24 +60,24 @@ 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) oscommands.ICmdObj {
@@ -179,7 +179,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
}
@@ -188,7 +188,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

@@ -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,19 +55,19 @@ 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"},
},
@@ -80,20 +80,20 @@ func TestStashStore(t *testing.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()
}
@@ -153,8 +153,8 @@ func TestStashRename(t *testing.T) {
testName string
index int
message string
expectedShaCmd []string
shaResult string
expectedHashCmd []string
hashResult string
expectedDropCmd []string
expectedStoreCmd []string
}
@@ -164,8 +164,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"},
},
@@ -173,8 +173,8 @@ 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"},
},
@@ -184,7 +184,7 @@ func TestStashRename(t *testing.T) {
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})

View File

@@ -3,6 +3,7 @@ package git_commands
import (
"fmt"
"os"
"path"
"github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -232,7 +233,8 @@ func (self *WorkingTreeCommands) Ignore(filename string) error {
// Exclude adds a file to the .git/info/exclude for the repo
func (self *WorkingTreeCommands) Exclude(filename string) error {
return self.os.AppendLineToFile(".git/info/exclude", filename)
excludeFile := path.Join(self.repoPaths.repoGitDirPath, "info", "exclude")
return self.os.AppendLineToFile(excludeFile, filename)
}
// WorktreeFileDiff returns the diff of a file
@@ -311,8 +313,8 @@ func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reve
}
// CheckoutFile checks out the file for the given commit
func (self *WorkingTreeCommands) CheckoutFile(commitSha, fileName string) error {
cmdArgs := NewGitCmd("checkout").Arg(commitSha, "--", fileName).
func (self *WorkingTreeCommands) CheckoutFile(commitHash, fileName string) error {
cmdArgs := NewGitCmd("checkout").Arg(commitHash, "--", fileName).
ToArgv()
return self.cmd.New(cmdArgs).Run()

View File

@@ -397,18 +397,18 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
func TestWorkingTreeCheckoutFile(t *testing.T) {
type scenario struct {
testName string
commitSha string
fileName string
runner *oscommands.FakeCmdObjRunner
test func(error)
testName string
commitHash string
fileName string
runner *oscommands.FakeCmdObjRunner
test func(error)
}
scenarios := []scenario{
{
testName: "typical case",
commitSha: "11af912",
fileName: "test999.txt",
testName: "typical case",
commitHash: "11af912",
fileName: "test999.txt",
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"checkout", "11af912", "--", "test999.txt"}, "", nil),
test: func(err error) {
@@ -416,9 +416,9 @@ func TestWorkingTreeCheckoutFile(t *testing.T) {
},
},
{
testName: "returns error if there is one",
commitSha: "11af912",
fileName: "test999.txt",
testName: "returns error if there is one",
commitHash: "11af912",
fileName: "test999.txt",
runner: oscommands.NewFakeRunner(t).
ExpectGitArgs([]string{"checkout", "11af912", "--", "test999.txt"}, "", errors.New("error")),
test: func(err error) {
@@ -432,7 +432,7 @@ func TestWorkingTreeCheckoutFile(t *testing.T) {
t.Run(s.testName, func(t *testing.T) {
instance := buildWorkingTreeCommands(commonDeps{runner: s.runner})
s.test(instance.CheckoutFile(s.commitSha, s.fileName))
s.test(instance.CheckoutFile(s.commitHash, s.fileName))
s.runner.CheckForMissingCalls()
})
}

View File

@@ -14,7 +14,7 @@ var githubServiceDef = ServiceDefinition{
provider: "github",
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}?expand=1",
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}?expand=1",
commitURL: "/commit/{{.CommitSha}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
repoURLTemplate: defaultRepoURLTemplate,
}
@@ -23,7 +23,7 @@ var bitbucketServiceDef = ServiceDefinition{
provider: "bitbucket",
pullRequestURLIntoDefaultBranch: "/pull-requests/new?source={{.From}}&t=1",
pullRequestURLIntoTargetBranch: "/pull-requests/new?source={{.From}}&dest={{.To}}&t=1",
commitURL: "/commits/{{.CommitSha}}",
commitURL: "/commits/{{.CommitHash}}",
regexStrings: []string{
`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^.*@.*:(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
@@ -35,7 +35,7 @@ var gitLabServiceDef = ServiceDefinition{
provider: "gitlab",
pullRequestURLIntoDefaultBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}",
pullRequestURLIntoTargetBranch: "/-/merge_requests/new?merge_request[source_branch]={{.From}}&merge_request[target_branch]={{.To}}",
commitURL: "/-/commit/{{.CommitSha}}",
commitURL: "/-/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
repoURLTemplate: defaultRepoURLTemplate,
}
@@ -44,7 +44,7 @@ var azdoServiceDef = ServiceDefinition{
provider: "azuredevops",
pullRequestURLIntoDefaultBranch: "/pullrequestcreate?sourceRef={{.From}}",
pullRequestURLIntoTargetBranch: "/pullrequestcreate?sourceRef={{.From}}&targetRef={{.To}}",
commitURL: "/commit/{{.CommitSha}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: []string{
`^git@ssh.dev.azure.com.*/(?P<org>.*)/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
@@ -56,7 +56,7 @@ var bitbucketServerServiceDef = ServiceDefinition{
provider: "bitbucketServer",
pullRequestURLIntoDefaultBranch: "/pull-requests?create&sourceBranch={{.From}}",
pullRequestURLIntoTargetBranch: "/pull-requests?create&targetBranch={{.To}}&sourceBranch={{.From}}",
commitURL: "/commits/{{.CommitSha}}",
commitURL: "/commits/{{.CommitHash}}",
regexStrings: []string{
`^ssh://git@.*/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
@@ -68,7 +68,7 @@ var giteaServiceDef = ServiceDefinition{
provider: "gitea",
pullRequestURLIntoDefaultBranch: "/compare/{{.From}}",
pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}",
commitURL: "/commit/{{.CommitSha}}",
commitURL: "/commit/{{.CommitHash}}",
regexStrings: defaultUrlRegexStrings,
repoURLTemplate: defaultRepoURLTemplate,
}

View File

@@ -51,13 +51,13 @@ func (self *HostingServiceMgr) GetPullRequestURL(from string, to string) (string
}
}
func (self *HostingServiceMgr) GetCommitURL(commitSha string) (string, error) {
func (self *HostingServiceMgr) GetCommitURL(commitHash string) (string, error) {
gitService, err := self.getService()
if err != nil {
return "", err
}
pullRequestURL := gitService.getCommitURL(commitSha)
pullRequestURL := gitService.getCommitURL(commitHash)
return pullRequestURL, nil
}
@@ -174,8 +174,8 @@ func (self *Service) getPullRequestURLIntoTargetBranch(from string, to string) s
return self.resolveUrl(self.pullRequestURLIntoTargetBranch, map[string]string{"From": from, "To": to})
}
func (self *Service) getCommitURL(commitSha string) string {
return self.resolveUrl(self.commitURL, map[string]string{"CommitSha": commitSha})
func (self *Service) getCommitURL(commitHash string) string {
return self.resolveUrl(self.commitURL, map[string]string{"CommitHash": commitHash})
}
func (self *Service) resolveUrl(templateString string, args map[string]string) string {

View File

@@ -3,8 +3,8 @@ package models
import (
"fmt"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stefanhaller/git-todo-parser/todo"
)
// Special commit hash for empty tree object
@@ -43,7 +43,7 @@ const (
// Commit : A git commit
type Commit struct {
Sha string
Hash string
Name string
Status CommitStatus
Action todo.TodoCommand
@@ -54,20 +54,20 @@ type Commit struct {
UnixTimestamp int64
Divergence Divergence // set to DivergenceNone unless we are showing the divergence view
// SHAs of parent commits (will be multiple if it's a merge commit)
// Hashes of parent commits (will be multiple if it's a merge commit)
Parents []string
}
func (c *Commit) ShortSha() string {
return utils.ShortSha(c.Sha)
func (c *Commit) ShortHash() string {
return utils.ShortHash(c.Hash)
}
func (c *Commit) FullRefName() string {
return c.Sha
return c.Hash
}
func (c *Commit) RefName() string {
return c.Sha
return c.Hash
}
func (c *Commit) ParentRefName() string {
@@ -86,7 +86,7 @@ func (c *Commit) ID() string {
}
func (c *Commit) Description() string {
return fmt.Sprintf("%s %s", c.Sha[:7], c.Name)
return fmt.Sprintf("%s %s", c.Hash[:7], c.Name)
}
func (c *Commit) IsMerge() bool {

View File

@@ -220,9 +220,6 @@ func (self *cmdObjRunner) runAndStreamAux(
cmdObj ICmdObj,
onRun func(*cmdHandler, io.Writer),
) error {
// if we're streaming this we don't want any fancy terminal stuff
cmdObj.AddEnvVars("TERM=dumb")
cmdWriter := self.guiIO.newCmdWriterFn()
if cmdObj.ShouldLog() {

View File

@@ -1,7 +1,7 @@
package oscommands
import (
"fmt"
"errors"
"io"
"os"
"path/filepath"
@@ -86,7 +86,7 @@ func CopyDir(src string, dst string) (err error) {
return err
}
if !si.IsDir() {
return fmt.Errorf("source is not a directory")
return errors.New("source is not a directory")
}
_, err = os.Stat(dst)

View File

@@ -33,7 +33,7 @@ type (
// PatchBuilder manages the building of a patch for a commit to be applied to another commit (or the working tree, or removed from the current commit). We also support building patches from things like stashes, for which there is less flexibility
type PatchBuilder struct {
// To is the commit sha if we're dealing with files of a commit, or a stash ref for a stash
// To is the commit hash if we're dealing with files of a commit, or a stash ref for a stash
To string
From string
reverse bool
@@ -46,7 +46,7 @@ type PatchBuilder struct {
fileInfoMap map[string]*fileInfo
Log *logrus.Entry
// loadFileDiff loads the diff of a file, for a given to (typically a commit SHA)
// loadFileDiff loads the diff of a file, for a given to (typically a commit hash)
loadFileDiff loadFileDiffFunc
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/adrg/xdg"
"github.com/jesseduffield/lazygit/pkg/utils/yaml_utils"
yaml "github.com/jesseduffield/yaml"
"gopkg.in/yaml.v3"
)
// AppConfig contains the base configuration fields required for lazygit.
@@ -164,6 +164,10 @@ func loadUserConfig(configFiles []string, base *UserConfig) (*UserConfig, error)
if err := yaml.Unmarshal(content, base); err != nil {
return nil, fmt.Errorf("The config at `%s` couldn't be parsed, please inspect it before opening up an issue.\n%w", path, err)
}
if err := base.Validate(); err != nil {
return nil, fmt.Errorf("The config at `%s` has a validation error.\n%w", path, err)
}
}
return base, nil
@@ -180,6 +184,11 @@ func migrateUserConfig(path string, content []byte) ([]byte, error) {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}
changedContent, err = changeNullKeybindingsToDisabled(changedContent)
if err != nil {
return nil, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
}
// Add more migrations here...
// Write config back if changed
@@ -193,6 +202,17 @@ func migrateUserConfig(path string, content []byte) ([]byte, error) {
return content, nil
}
func changeNullKeybindingsToDisabled(changedContent []byte) ([]byte, error) {
return yaml_utils.Walk(changedContent, func(node *yaml.Node, path string) bool {
if strings.HasPrefix(path, "keybinding.") && node.Kind == yaml.ScalarNode && node.Tag == "!!null" {
node.Value = "<disabled>"
node.Tag = "!!str"
return true
}
return false
})
}
func (c *AppConfig) GetDebug() bool {
return c.Debug
}

View File

@@ -1,7 +1,7 @@
package config
import (
yaml "github.com/jesseduffield/yaml"
"gopkg.in/yaml.v3"
)
// NewDummyAppConfig creates a new dummy AppConfig for testing

View File

@@ -145,6 +145,11 @@ type GuiConfig struct {
// How things are filtered when typing '/'.
// One of 'substring' (default) | 'fuzzy'
FilterMode string `yaml:"filterMode" jsonschema:"enum=substring,enum=fuzzy"`
// Config relating to the spinner.
Spinner SpinnerConfig `yaml:"spinner"`
// Status panel view.
// One of 'dashboard' (default) | 'allBranchesLog'
StatusPanelView string `yaml:"statusPanelView" jsonschema:"enum=dashboard,enum=allBranchesLog"`
}
func (c *GuiConfig) UseFuzzySearch() bool {
@@ -182,6 +187,13 @@ type CommitLengthConfig struct {
Show bool `yaml:"show"`
}
type SpinnerConfig struct {
// The frames of the spinner animation.
Frames []string `yaml:"frames"`
// The "speed" of the spinner in milliseconds.
Rate int `yaml:"rate" jsonschema:"minimum=1"`
}
type GitConfig struct {
// See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md
Paging PagingConfig `yaml:"paging"`
@@ -671,6 +683,11 @@ func GetDefaultConfig() *UserConfig {
AnimateExplosion: true,
PortraitMode: "auto",
FilterMode: "substring",
Spinner: SpinnerConfig{
Frames: []string{"|", "/", "-", "\\"},
Rate: 50,
},
StatusPanelView: "dashboard",
},
Git: GitConfig{
Paging: PagingConfig{

View File

@@ -0,0 +1,22 @@
package config
import (
"fmt"
"slices"
"strings"
)
func (config *UserConfig) Validate() error {
if err := validateEnum("gui.statusPanelView", config.Gui.StatusPanelView, []string{"dashboard", "allBranchesLog"}); err != nil {
return err
}
return nil
}
func validateEnum(name string, value string, allowedValues []string) error {
if slices.Contains(allowedValues, value) {
return nil
}
allowedValuesStr := strings.Join(allowedValues, ", ")
return fmt.Errorf("Unexpected value '%s' for '%s'. Allowed values: %s", value, name, allowedValuesStr)
}

View File

@@ -0,0 +1,49 @@
package config
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUserConfigValidate_enums(t *testing.T) {
type testCase struct {
value string
valid bool
}
scenarios := []struct {
name string
setup func(config *UserConfig, value string)
testCases []testCase
}{
{
name: "Gui.StatusPanelView",
setup: func(config *UserConfig, value string) {
config.Gui.StatusPanelView = value
},
testCases: []testCase{
{value: "dashboard", valid: true},
{value: "allBranchesLog", valid: true},
{value: "", valid: false},
{value: "invalid_value", valid: false},
},
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
for _, testCase := range s.testCases {
config := GetDefaultConfig()
s.setup(config, testCase.value)
err := config.Validate()
if testCase.valid {
assert.NoError(t, err)
} else {
assert.Error(t, err)
}
}
})
}
}

View File

@@ -87,9 +87,10 @@ func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan stru
if self.pauseBackgroundRefreshes {
continue
}
self.gui.c.OnWorker(func(gocui.Task) {
self.gui.c.OnWorker(func(gocui.Task) error {
_ = function()
done <- struct{}{}
return nil
})
// waiting so that we don't bunch up refreshes if the refresh takes longer than the interval
<-done

View File

@@ -8,6 +8,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
type LocalCommitsContext struct {
@@ -28,12 +29,12 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
)
getDisplayStrings := func(startIdx int, endIdx int) [][]string {
selectedCommitSha := ""
selectedCommitHash := ""
if c.CurrentContext().GetKey() == LOCAL_COMMITS_CONTEXT_KEY {
selectedCommit := viewModel.GetSelected()
if selectedCommit != nil {
selectedCommitSha = selectedCommit.Sha
selectedCommitHash = selectedCommit.Hash
}
}
@@ -47,14 +48,14 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
c.Model().CheckedOutBranch,
hasRebaseUpdateRefsConfig,
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().CherryPicking.SelectedHashSet(),
c.Modes().Diffing.Ref,
c.Modes().MarkedBaseCommit.GetSha(),
c.Modes().MarkedBaseCommit.GetHash(),
c.UserConfig.Gui.TimeFormat,
c.UserConfig.Gui.ShortTimeFormat,
time.Now(),
c.UserConfig.Git.ParseEmoji,
selectedCommitSha,
selectedCommitHash,
startIdx,
endIdx,
shouldShowGraph(c),
@@ -125,6 +126,29 @@ func (self *LocalCommitsContext) GetSelectedRef() types.Ref {
return commit
}
// Returns the commit hash of the selected commit, or an empty string if no
// commit is selected
func (self *LocalCommitsContext) GetSelectedCommitHash() string {
commit := self.GetSelected()
if commit == nil {
return ""
}
return commit.Hash
}
func (self *LocalCommitsContext) SelectCommitByHash(hash string) bool {
if hash == "" {
return false
}
if _, idx, found := lo.FindIndexOf(self.GetItems(), func(c *models.Commit) bool { return c.Hash == hash }); found {
self.SetSelection(idx)
return true
}
return false
}
func (self *LocalCommitsContext) GetDiffTerminals() []string {
itemId := self.GetSelectedItemId()

View File

@@ -1,6 +1,8 @@
package context
import (
"errors"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@@ -74,9 +76,6 @@ func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem, columnAlignment
// TODO: move into presentation package
func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
menuItems := self.FilteredListViewModel.GetItems()
showKeys := lo.SomeBy(menuItems, func(item *types.MenuItem) bool {
return item.Key != nil
})
return lo.Map(menuItems, func(item *types.MenuItem, _ int) []string {
displayStrings := item.LabelColumns
@@ -84,12 +83,12 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
displayStrings[0] = style.FgDefault.SetStrikethrough().Sprint(displayStrings[0])
}
if !showKeys {
return displayStrings
keyLabel := ""
if item.Key != nil {
keyLabel = style.FgCyan.Sprint(keybindings.LabelFromKey(item.Key))
}
keyLabel := keybindings.LabelFromKey(item.Key)
displayStrings = utils.Prepend(displayStrings, style.FgCyan.Sprint(keyLabel))
displayStrings = utils.Prepend(displayStrings, keyLabel)
return displayStrings
})
}
@@ -151,7 +150,7 @@ func (self *MenuContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Bin
func (self *MenuContext) OnMenuPress(selectedItem *types.MenuItem) error {
if selectedItem != nil && selectedItem.DisabledReason != nil {
if selectedItem.DisabledReason.ShowErrorInPanel {
return self.c.ErrorMsg(selectedItem.DisabledReason.Text)
return errors.New(selectedItem.DisabledReason.Text)
}
self.c.ErrorToast(self.c.Tr.DisabledMenuItemPrefix + selectedItem.DisabledReason.Text)

View File

@@ -22,7 +22,7 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
viewModel := NewFilteredListViewModel(
func() []*models.Commit { return c.Model().FilteredReflogCommits },
func(commit *models.Commit) []string {
return []string{commit.ShortSha(), commit.Name}
return []string{commit.ShortHash(), commit.Name}
},
)
@@ -30,7 +30,7 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
return presentation.GetReflogCommitListDisplayStrings(
viewModel.GetItems(),
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().CherryPicking.SelectedHashSet(),
c.Modes().Diffing.Ref,
time.Now(),
c.UserConfig.Gui.TimeFormat,

View File

@@ -26,7 +26,7 @@ func NewRemotesContext(c *ContextCommon) *RemotesContext {
getDisplayStrings := func(_ int, _ int) [][]string {
return presentation.GetRemoteListDisplayStrings(
viewModel.GetItems(), c.Modes().Diffing.Ref, c.State().GetItemOperation, c.Tr)
viewModel.GetItems(), c.Modes().Diffing.Ref, c.State().GetItemOperation, c.Tr, c.UserConfig)
}
return &RemotesContext{

View File

@@ -44,11 +44,11 @@ func NewSubCommitsContext(
return [][]string{}
}
selectedCommitSha := ""
selectedCommitHash := ""
if c.CurrentContext().GetKey() == SUB_COMMITS_CONTEXT_KEY {
selectedCommit := viewModel.GetSelected()
if selectedCommit != nil {
selectedCommitSha = selectedCommit.Sha
selectedCommitHash = selectedCommit.Hash
}
}
branches := []*models.Branch{}
@@ -63,14 +63,14 @@ func NewSubCommitsContext(
viewModel.GetRef().RefName(),
hasRebaseUpdateRefsConfig,
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
c.Modes().CherryPicking.SelectedShaSet(),
c.Modes().CherryPicking.SelectedHashSet(),
c.Modes().Diffing.Ref,
"",
c.UserConfig.Gui.TimeFormat,
c.UserConfig.Gui.ShortTimeFormat,
time.Now(),
c.UserConfig.Git.ParseEmoji,
selectedCommitSha,
selectedCommitHash,
startIdx,
endIdx,
// Don't show the graph in the left/right view; we'd like to, but

View File

@@ -30,7 +30,7 @@ func NewTagsContext(
return presentation.GetTagListDisplayStrings(
viewModel.GetItems(),
c.State().GetItemOperation,
c.Modes().Diffing.Ref, c.Tr)
c.Modes().Diffing.Ref, c.Tr, c.UserConfig)
}
return &TagsContext{

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
@@ -125,9 +126,9 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard,
Items: []*types.MenuItem{
{
Label: self.c.Tr.CommitSha,
Label: self.c.Tr.CommitHash,
OnPress: func() error {
return self.copyCommitSHAToClipboard(commit)
return self.copyCommitHashToClipboard(commit)
},
},
{
@@ -169,25 +170,25 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
})
}
func (self *BasicCommitsController) copyCommitSHAToClipboard(commit *models.Commit) error {
self.c.LogAction(self.c.Tr.Actions.CopyCommitSHAToClipboard)
if err := self.c.OS().CopyToClipboard(commit.Sha); err != nil {
return self.c.Error(err)
func (self *BasicCommitsController) copyCommitHashToClipboard(commit *models.Commit) error {
self.c.LogAction(self.c.Tr.Actions.CopyCommitHashToClipboard)
if err := self.c.OS().CopyToClipboard(commit.Hash); err != nil {
return err
}
self.c.Toast(fmt.Sprintf("'%s' %s", commit.Sha, self.c.Tr.CopiedToClipboard))
self.c.Toast(fmt.Sprintf("'%s' %s", commit.Hash, self.c.Tr.CopiedToClipboard))
return nil
}
func (self *BasicCommitsController) copyCommitURLToClipboard(commit *models.Commit) error {
url, err := self.c.Helpers().Host.GetCommitURL(commit.Sha)
url, err := self.c.Helpers().Host.GetCommitURL(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.CopyCommitURLToClipboard)
if err := self.c.OS().CopyToClipboard(url); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.CommitURLCopiedToClipboard)
@@ -195,14 +196,14 @@ func (self *BasicCommitsController) copyCommitURLToClipboard(commit *models.Comm
}
func (self *BasicCommitsController) copyCommitDiffToClipboard(commit *models.Commit) error {
diff, err := self.c.Git().Commit.GetCommitDiff(commit.Sha)
diff, err := self.c.Git().Commit.GetCommitDiff(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.CopyCommitDiffToClipboard)
if err := self.c.OS().CopyToClipboard(diff); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.CommitDiffCopiedToClipboard)
@@ -210,16 +211,16 @@ func (self *BasicCommitsController) copyCommitDiffToClipboard(commit *models.Com
}
func (self *BasicCommitsController) copyAuthorToClipboard(commit *models.Commit) error {
author, err := self.c.Git().Commit.GetCommitAuthor(commit.Sha)
author, err := self.c.Git().Commit.GetCommitAuthor(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
formattedAuthor := fmt.Sprintf("%s <%s>", author.Name, author.Email)
self.c.LogAction(self.c.Tr.Actions.CopyCommitAuthorToClipboard)
if err := self.c.OS().CopyToClipboard(formattedAuthor); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.CommitAuthorCopiedToClipboard)
@@ -227,14 +228,14 @@ func (self *BasicCommitsController) copyAuthorToClipboard(commit *models.Commit)
}
func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.Commit) error {
message, err := self.c.Git().Commit.GetCommitMessage(commit.Sha)
message, err := self.c.Git().Commit.GetCommitMessage(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageToClipboard)
if err := self.c.OS().CopyToClipboard(message); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.CommitMessageCopiedToClipboard)
@@ -242,14 +243,14 @@ func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.
}
func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.Commit) error {
message, err := self.c.Git().Commit.GetCommitSubject(commit.Sha)
message, err := self.c.Git().Commit.GetCommitSubject(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.CopyCommitSubjectToClipboard)
if err := self.c.OS().CopyToClipboard(message); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.CommitSubjectCopiedToClipboard)
@@ -257,14 +258,14 @@ func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.
}
func (self *BasicCommitsController) openInBrowser(commit *models.Commit) error {
url, err := self.c.Helpers().Host.GetCommitURL(commit.Sha)
url, err := self.c.Helpers().Host.GetCommitURL(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.OpenCommitInBrowser)
if err := self.c.OS().OpenLink(url); err != nil {
return self.c.Error(err)
return err
}
return nil
@@ -275,7 +276,7 @@ func (self *BasicCommitsController) newBranch(commit *models.Commit) error {
}
func (self *BasicCommitsController) createResetMenu(commit *models.Commit) error {
return self.c.Helpers().Refs.CreateGitResetMenu(commit.Sha)
return self.c.Helpers().Refs.CreateGitResetMenu(commit.Hash)
}
func (self *BasicCommitsController) checkout(commit *models.Commit) error {
@@ -284,7 +285,7 @@ func (self *BasicCommitsController) checkout(commit *models.Commit) error {
Prompt: self.c.Tr.SureCheckoutThisCommit,
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.CheckoutCommit)
return self.c.Helpers().Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{})
return self.c.Helpers().Refs.CheckoutRef(commit.Hash, types.CheckoutRefOptions{})
},
})
}
@@ -295,7 +296,7 @@ func (self *BasicCommitsController) copyRange(*models.Commit) error {
func (self *BasicCommitsController) canCopyCommits(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
for _, commit := range selectedCommits {
if commit.Sha == "" {
if commit.Hash == "" {
return &types.DisabledReason{Text: self.c.Tr.CannotCherryPickNonCommit, ShowErrorInPanel: true}
}
@@ -314,7 +315,7 @@ func (self *BasicCommitsController) handleOldCherryPickKey() error {
"paste": keybindings.Label(self.c.UserConfig.Keybinding.Commits.PasteCommits),
})
return self.c.ErrorMsg(msg)
return errors.New(msg)
}
func (self *BasicCommitsController) openDiffTool(commit *models.Commit) error {

View File

@@ -69,18 +69,18 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
// Originally we were allowing the user to, from the bisect menu, select whether
// they were talking about the selected commit or the current bisect commit,
// and that was a bit confusing (and required extra keypresses).
selectCurrentAfter := info.GetCurrentSha() == "" || info.GetCurrentSha() == commit.Sha
selectCurrentAfter := info.GetCurrentHash() == "" || info.GetCurrentHash() == commit.Hash
// we need to wait to reselect if our bisect commits aren't ancestors of our 'start'
// ref, because we'll be reloading our commits in that case.
waitToReselect := selectCurrentAfter && !self.c.Git().Bisect.ReachableFromStart(info)
// If we have a current sha already, then we always want to use that one. If
// If we have a current hash already, then we always want to use that one. If
// not, we're still picking the initial commits before we really start, so
// use the selected commit in that case.
bisecting := info.GetCurrentSha() != ""
shaToMark := lo.Ternary(bisecting, info.GetCurrentSha(), commit.Sha)
shortShaToMark := utils.ShortSha(shaToMark)
bisecting := info.GetCurrentHash() != ""
hashToMark := lo.Ternary(bisecting, info.GetCurrentHash(), commit.Hash)
shortHashToMark := utils.ShortHash(hashToMark)
// For marking a commit as bad, when we're not already bisecting, we require
// a single item selected, but once we are bisecting, it doesn't matter because
@@ -92,11 +92,11 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
menuItems := []*types.MenuItem{
{
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortShaToMark, info.NewTerm()),
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortHashToMark, info.NewTerm()),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.BisectMark)
if err := self.c.Git().Bisect.Mark(shaToMark, info.NewTerm()); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Mark(hashToMark, info.NewTerm()); err != nil {
return err
}
return self.afterMark(selectCurrentAfter, waitToReselect)
@@ -105,11 +105,11 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
Key: 'b',
},
{
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortShaToMark, info.OldTerm()),
Label: fmt.Sprintf(self.c.Tr.Bisect.Mark, shortHashToMark, info.OldTerm()),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.BisectMark)
if err := self.c.Git().Bisect.Mark(shaToMark, info.OldTerm()); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Mark(hashToMark, info.OldTerm()); err != nil {
return err
}
return self.afterMark(selectCurrentAfter, waitToReselect)
@@ -118,11 +118,11 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
Key: 'g',
},
{
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortShaToMark),
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipCurrent, shortHashToMark),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.BisectSkip)
if err := self.c.Git().Bisect.Skip(shaToMark); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Skip(hashToMark); err != nil {
return err
}
return self.afterMark(selectCurrentAfter, waitToReselect)
@@ -131,13 +131,13 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c
Key: 's',
},
}
if info.GetCurrentSha() != "" && info.GetCurrentSha() != commit.Sha {
if info.GetCurrentHash() != "" && info.GetCurrentHash() != commit.Hash {
menuItems = append(menuItems, lo.ToPtr(types.MenuItem{
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipSelected, commit.ShortSha()),
Label: fmt.Sprintf(self.c.Tr.Bisect.SkipSelected, commit.ShortHash()),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.BisectSkip)
if err := self.c.Git().Bisect.Skip(commit.Sha); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Skip(commit.Hash); err != nil {
return err
}
return self.afterMark(selectCurrentAfter, waitToReselect)
@@ -165,15 +165,15 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
Title: self.c.Tr.Bisect.BisectMenuTitle,
Items: []*types.MenuItem{
{
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()),
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortHash(), info.NewTerm()),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.StartBisect)
if err := self.c.Git().Bisect.Start(); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Git().Bisect.Mark(commit.Sha, info.NewTerm()); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Mark(commit.Hash, info.NewTerm()); err != nil {
return err
}
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
@@ -182,15 +182,15 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
Key: 'b',
},
{
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.OldTerm()),
Label: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortHash(), info.OldTerm()),
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.StartBisect)
if err := self.c.Git().Bisect.Start(); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Git().Bisect.Mark(commit.Sha, info.OldTerm()); err != nil {
return self.c.Error(err)
if err := self.c.Git().Bisect.Mark(commit.Hash, info.OldTerm()); err != nil {
return err
}
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
@@ -209,7 +209,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
HandleConfirm: func(newTerm string) error {
self.c.LogAction(self.c.Tr.Actions.StartBisect)
if err := self.c.Git().Bisect.StartWithTerms(oldTerm, newTerm); err != nil {
return self.c.Error(err)
return err
}
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
@@ -224,15 +224,15 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
})
}
func (self *BisectController) showBisectCompleteMessage(candidateShas []string) error {
func (self *BisectController) showBisectCompleteMessage(candidateHashes []string) error {
prompt := self.c.Tr.Bisect.CompletePrompt
if len(candidateShas) > 1 {
if len(candidateHashes) > 1 {
prompt = self.c.Tr.Bisect.CompletePromptIndeterminate
}
formattedCommits, err := self.c.Git().Commit.GetCommitsOneline(candidateShas)
formattedCommits, err := self.c.Git().Commit.GetCommitsOneline(candidateHashes)
if err != nil {
return self.c.Error(err)
return err
}
return self.c.Confirm(types.ConfirmOpts{
@@ -241,7 +241,7 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string)
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.ResetBisect)
if err := self.c.Git().Bisect.Reset(); err != nil {
return self.c.Error(err)
return err
}
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
@@ -250,33 +250,34 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string)
}
func (self *BisectController) afterMark(selectCurrent bool, waitToReselect bool) error {
done, candidateShas, err := self.c.Git().Bisect.IsDone()
done, candidateHashes, err := self.c.Git().Bisect.IsDone()
if err != nil {
return self.c.Error(err)
return err
}
if err := self.afterBisectMarkRefresh(selectCurrent, waitToReselect); err != nil {
return self.c.Error(err)
return err
}
if done {
return self.showBisectCompleteMessage(candidateShas)
return self.showBisectCompleteMessage(candidateHashes)
}
return nil
}
func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToReselect bool) error {
selectFn := func() {
selectFn := func() error {
if selectCurrent {
self.selectCurrentBisectCommit()
}
return nil
}
if waitToReselect {
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{}, Then: selectFn})
} else {
selectFn()
_ = selectFn()
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
}
@@ -284,10 +285,10 @@ func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToR
func (self *BisectController) selectCurrentBisectCommit() {
info := self.c.Git().Bisect.GetInfo()
if info.GetCurrentSha() != "" {
// find index of commit with that sha, move cursor to that.
if info.GetCurrentHash() != "" {
// find index of commit with that hash, move cursor to that.
for i, commit := range self.c.Model().Commits {
if commit.Sha == info.GetCurrentSha() {
if commit.Hash == info.GetCurrentHash() {
self.context().SetSelection(i)
_ = self.context().HandleFocus(types.OnFocusOpts{})
break

View File

@@ -209,7 +209,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
LabelColumns: []string{self.c.Tr.UnsetUpstream},
OnPress: func() error {
if err := self.c.Git().Branch.UnsetUpstream(selectedBranch.Name); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Refresh(types.RefreshOptions{
Mode: types.SYNC,
@@ -218,7 +218,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
types.COMMITS,
},
}); err != nil {
return self.c.Error(err)
return err
}
return nil
},
@@ -231,11 +231,11 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
return self.c.Helpers().Upstream.PromptForUpstreamWithoutInitialContent(selectedBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
if err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Git().Branch.SetUpstream(upstreamRemote, upstreamBranch, selectedBranch.Name); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Refresh(types.RefreshOptions{
Mode: types.SYNC,
@@ -244,7 +244,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
types.COMMITS,
},
}); err != nil {
return self.c.Error(err)
return err
}
return nil
})
@@ -279,7 +279,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
OnPress: func() error {
err := self.c.Helpers().Refs.CreateGitResetMenu(upstream)
if err != nil {
return self.c.Error(err)
return err
}
return nil
},
@@ -292,7 +292,7 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
OpensMenu: true,
OnPress: func() error {
if err := self.c.Helpers().MergeAndRebase.RebaseOntoRef(selectedBranch.ShortUpstreamRefName()); err != nil {
return self.c.Error(err)
return err
}
return nil
},
@@ -334,7 +334,7 @@ func (self *BranchesController) context() *context.BranchesContext {
func (self *BranchesController) press(selectedBranch *models.Branch) error {
if selectedBranch == self.c.Helpers().Refs.GetCheckedOutRef() {
return self.c.ErrorMsg(self.c.Tr.AlreadyCheckedOutBranch)
return errors.New(self.c.Tr.AlreadyCheckedOutBranch)
}
worktreeForRef, ok := self.worktreeForBranch(selectedBranch)
@@ -378,7 +378,7 @@ func (self *BranchesController) promptToCheckoutWorktree(worktree *models.Worktr
func (self *BranchesController) handleCreatePullRequest(selectedBranch *models.Branch) error {
if !selectedBranch.IsTrackingRemote() {
return self.c.ErrorMsg(self.c.Tr.PullRequestNoUpstream)
return errors.New(self.c.Tr.PullRequestNoUpstream)
}
return self.createPullRequest(selectedBranch.UpstreamBranch, "")
}
@@ -395,16 +395,16 @@ func (self *BranchesController) copyPullRequestURL() error {
branchExistsOnRemote := self.c.Git().Remote.CheckRemoteBranchExists(branch.Name)
if !branchExistsOnRemote {
return self.c.Error(errors.New(self.c.Tr.NoBranchOnRemote))
return errors.New(self.c.Tr.NoBranchOnRemote)
}
url, err := self.c.Helpers().Host.GetPullRequestURL(branch.Name, "")
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.CopyPullRequestURL)
if err := self.c.OS().CopyToClipboard(url); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.PullRequestURLCopiedToClipboard)
@@ -423,7 +423,7 @@ func (self *BranchesController) forceCheckout() error {
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.ForceCheckoutBranch)
if err := self.c.Git().Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
},
@@ -463,7 +463,7 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
}
if err := self.c.Git().Branch.New(newBranchName, branch.FullRefName()); err != nil {
return self.c.Error(err)
return err
}
self.context().SetSelection(0)
@@ -524,7 +524,7 @@ func (self *BranchesController) localDelete(branch *models.Branch) error {
return self.forceDelete(branch)
}
if err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
})
@@ -548,7 +548,7 @@ func (self *BranchesController) forceDelete(branch *models.Branch) error {
Prompt: message,
HandleConfirm: func() error {
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
return self.c.ErrorMsg(err.Error())
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
},
@@ -615,13 +615,13 @@ func (self *BranchesController) notRebasingOntoSelf(branch *models.Branch) *type
func (self *BranchesController) fastForward(branch *models.Branch) error {
if !branch.IsTrackingRemote() {
return self.c.ErrorMsg(self.c.Tr.FwdNoUpstream)
return errors.New(self.c.Tr.FwdNoUpstream)
}
if !branch.RemoteBranchStoredLocally() {
return self.c.ErrorMsg(self.c.Tr.FwdNoLocalUpstream)
return errors.New(self.c.Tr.FwdNoLocalUpstream)
}
if branch.HasCommitsToPush() {
return self.c.ErrorMsg(self.c.Tr.FwdCommitsToPush)
return errors.New(self.c.Tr.FwdCommitsToPush)
}
action := self.c.Tr.Actions.FastForwardBranch
@@ -688,7 +688,7 @@ func (self *BranchesController) rename(branch *models.Branch) error {
HandleConfirm: func(newBranchName string) error {
self.c.LogAction(self.c.Tr.Actions.RenameBranch)
if err := self.c.Git().Branch.Rename(branch.Name, helpers.SanitizedBranchName(newBranchName)); err != nil {
return self.c.Error(err)
return err
}
// need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch
@@ -766,7 +766,7 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra
LabelColumns: fromToLabelColumns(checkedOutBranch.Name, selectedBranch.Name),
OnPress: func() error {
if !checkedOutBranch.IsTrackingRemote() || !selectedBranch.IsTrackingRemote() {
return self.c.ErrorMsg(self.c.Tr.PullRequestNoUpstream)
return errors.New(self.c.Tr.PullRequestNoUpstream)
}
return self.createPullRequest(checkedOutBranch.UpstreamBranch, selectedBranch.UpstreamBranch)
},
@@ -783,13 +783,13 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra
func (self *BranchesController) createPullRequest(from string, to string) error {
url, err := self.c.Helpers().Host.GetPullRequestURL(from, to)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.OpenPullRequest)
if err := self.c.OS().OpenLink(url); err != nil {
return self.c.Error(err)
return err
}
return nil

View File

@@ -1,6 +1,8 @@
package controllers
import (
"errors"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
@@ -114,7 +116,7 @@ func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, e
if err == git_commands.ErrInvalidCommitIndex {
return false, nil
}
return false, self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr)
return false, errors.New(self.c.Tr.CommitWithoutMessageErr)
}
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"strings"
"github.com/jesseduffield/gocui"
@@ -170,7 +171,7 @@ func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts)
func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error {
self.c.LogAction(self.c.Tr.Actions.CheckoutFile)
if err := self.c.Git().WorkingTree.CheckoutFile(self.context().GetRef().RefName(), node.GetPath()); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
@@ -179,7 +180,7 @@ func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error
func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileNode) error {
parentContext, ok := self.c.CurrentContext().GetParentContext()
if !ok || parentContext.GetKey() != context.LOCAL_COMMITS_CONTEXT_KEY {
return self.c.ErrorMsg(self.c.Tr.CanOnlyDiscardFromLocalCommits)
return errors.New(self.c.Tr.CanOnlyDiscardFromLocalCommits)
}
if ok, err := self.c.Helpers().PatchBuilding.ValidateNormalWorkingTreeState(); !ok {
@@ -208,7 +209,7 @@ func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileN
return nil
})
if err != nil {
return self.c.Error(err)
return err
}
}
@@ -294,7 +295,7 @@ func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.Comm
return patchOperationFunction(file.Name)
})
if err != nil {
return self.c.Error(err)
return err
}
}

View File

@@ -65,7 +65,7 @@ func (self *ContextLinesController) Context() types.Context {
func (self *ContextLinesController) Increase() error {
if self.isShowingDiff() {
if err := self.checkCanChangeContext(); err != nil {
return self.c.Error(err)
return err
}
self.c.AppState.DiffContextSize++
@@ -80,7 +80,7 @@ func (self *ContextLinesController) Decrease() error {
if self.isShowingDiff() && old_size > 1 {
if err := self.checkCanChangeContext(); err != nil {
return self.c.Error(err)
return err
}
self.c.AppState.DiffContextSize = old_size - 1

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"fmt"
"github.com/jesseduffield/gocui"
@@ -15,11 +16,11 @@ type CustomPatchOptionsMenuAction struct {
func (self *CustomPatchOptionsMenuAction) Call() error {
if !self.c.Git().Patch.PatchBuilder.Active() {
return self.c.ErrorMsg(self.c.Tr.NoPatchError)
return errors.New(self.c.Tr.NoPatchError)
}
if self.c.Git().Patch.PatchBuilder.IsEmpty() {
return self.c.ErrorMsg(self.c.Tr.EmptyPatchError)
return errors.New(self.c.Tr.EmptyPatchError)
}
menuItems := []*types.MenuItem{
@@ -67,7 +68,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
if self.c.CurrentContext().GetKey() == self.c.Contexts().LocalCommits.GetKey() {
selectedCommit := self.c.Contexts().LocalCommits.GetSelected()
if selectedCommit != nil && self.c.Git().Patch.PatchBuilder.To != selectedCommit.Sha {
if selectedCommit != nil && self.c.Git().Patch.PatchBuilder.To != selectedCommit.Hash {
var disabledReason *types.DisabledReason
if self.c.Contexts().LocalCommits.AreMultipleItemsSelected() {
@@ -80,7 +81,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
append(
[]*types.MenuItem{
{
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Sha),
Label: fmt.Sprintf(self.c.Tr.MovePatchToSelectedCommit, selectedCommit.Hash),
Tooltip: self.c.Tr.MovePatchToSelectedCommitTooltip,
OnPress: self.handleMovePatchToSelectedCommit,
Key: 'm',
@@ -106,7 +107,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
for index, commit := range self.c.Model().Commits {
if commit.Sha == self.c.Git().Patch.PatchBuilder.To {
if commit.Hash == self.c.Git().Patch.PatchBuilder.To {
return index
}
}
@@ -115,7 +116,7 @@ func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
func (self *CustomPatchOptionsMenuAction) validateNormalWorkingTreeState() (bool, error) {
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
return false, self.c.ErrorMsg(self.c.Tr.CantPatchWhileRebasingError)
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
}
return true, nil
}
@@ -234,7 +235,7 @@ func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error {
}
self.c.LogAction(action)
if err := self.c.Git().Patch.ApplyCustomPatch(reverse); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}
@@ -244,7 +245,7 @@ func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
self.c.LogAction(self.c.Tr.Actions.CopyPatchToClipboard)
if err := self.c.OS().CopyToClipboard(patch); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.PatchCopiedToClipboard)

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"strings"
"github.com/jesseduffield/gocui"
@@ -388,7 +389,7 @@ func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) e
// if any files within have inline merge conflicts we can't stage or unstage,
// or it'll end up with those >>>>>> lines actually staged
if node.GetHasInlineMergeConflicts() {
return self.c.ErrorMsg(self.c.Tr.ErrStageDirWithInlineMergeConflicts)
return errors.New(self.c.Tr.ErrStageDirWithInlineMergeConflicts)
}
}
@@ -410,7 +411,7 @@ func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) e
}
if err := self.c.Git().WorkingTree.StageFiles(toPaths(selectedNodes)); err != nil {
return self.c.Error(err)
return err
}
} else {
self.c.LogAction(self.c.Tr.Actions.UnstageFile)
@@ -428,13 +429,13 @@ func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) e
if len(untrackedNodes) > 0 {
if err := self.c.Git().WorkingTree.UnstageUntrackedFiles(toPaths(untrackedNodes)); err != nil {
return self.c.Error(err)
return err
}
}
if len(trackedNodes) > 0 {
if err := self.c.Git().WorkingTree.UnstageTrackedFiles(toPaths(trackedNodes)); err != nil {
return self.c.Error(err)
return err
}
}
}
@@ -496,7 +497,7 @@ func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
return self.switchToMerge()
}
if file.HasMergeConflicts {
return self.c.ErrorMsg(self.c.Tr.FileStagingRequirements)
return errors.New(self.c.Tr.FileStagingRequirements)
}
return self.c.PushContext(self.c.Contexts().Staging, opts)
@@ -523,7 +524,7 @@ func (self *FilesController) toggleStagedAllWithLock() error {
// if any files within have inline merge conflicts we can't stage or unstage,
// or it'll end up with those >>>>>> lines actually staged
if root.GetHasInlineMergeConflicts() {
return self.c.ErrorMsg(self.c.Tr.ErrStageDirWithInlineMergeConflicts)
return errors.New(self.c.Tr.ErrStageDirWithInlineMergeConflicts)
}
if root.GetHasUnstagedChanges() {
@@ -534,7 +535,7 @@ func (self *FilesController) toggleStagedAllWithLock() error {
}
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
return self.c.Error(err)
return err
}
} else {
self.c.LogAction(self.c.Tr.Actions.UnstageAllFiles)
@@ -544,7 +545,7 @@ func (self *FilesController) toggleStagedAllWithLock() error {
}
if err := self.c.Git().WorkingTree.UnstageAll(); err != nil {
return self.c.Error(err)
return err
}
}
@@ -606,30 +607,17 @@ func (self *FilesController) ignoreOrExcludeFile(node *filetree.FileNode, trText
func (self *FilesController) ignore(node *filetree.FileNode) error {
if node.GetPath() == ".gitignore" {
return self.c.ErrorMsg(self.c.Tr.Actions.IgnoreFileErr)
return errors.New(self.c.Tr.Actions.IgnoreFileErr)
}
err := self.ignoreOrExcludeFile(node, self.c.Tr.IgnoreTracked, self.c.Tr.IgnoreTrackedPrompt, self.c.Tr.Actions.IgnoreExcludeFile, self.c.Git().WorkingTree.Ignore)
if err != nil {
return err
}
return nil
return self.ignoreOrExcludeFile(node, self.c.Tr.IgnoreTracked, self.c.Tr.IgnoreTrackedPrompt, self.c.Tr.Actions.IgnoreExcludeFile, self.c.Git().WorkingTree.Ignore)
}
func (self *FilesController) exclude(node *filetree.FileNode) error {
if node.GetPath() == ".git/info/exclude" {
return self.c.ErrorMsg(self.c.Tr.Actions.ExcludeFileErr)
}
if node.GetPath() == ".gitignore" {
return self.c.ErrorMsg(self.c.Tr.Actions.ExcludeGitIgnoreErr)
return errors.New(self.c.Tr.Actions.ExcludeGitIgnoreErr)
}
err := self.ignoreOrExcludeFile(node, self.c.Tr.ExcludeTracked, self.c.Tr.ExcludeTrackedPrompt, self.c.Tr.Actions.ExcludeFile, self.c.Git().WorkingTree.Exclude)
if err != nil {
return err
}
return nil
return self.ignoreOrExcludeFile(node, self.c.Tr.ExcludeTracked, self.c.Tr.ExcludeTrackedPrompt, self.c.Tr.Actions.ExcludeFile, self.c.Git().WorkingTree.Exclude)
}
func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error {
@@ -640,7 +628,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
LabelColumns: []string{self.c.Tr.IgnoreFile},
OnPress: func() error {
if err := self.ignore(node); err != nil {
return self.c.Error(err)
return err
}
return nil
},
@@ -650,7 +638,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
LabelColumns: []string{self.c.Tr.ExcludeFile},
OnPress: func() error {
if err := self.exclude(node); err != nil {
return self.c.Error(err)
return err
}
return nil
},
@@ -671,7 +659,7 @@ func (self *FilesController) handleAmendCommitPress() error {
HandleConfirm: func() error {
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
if len(self.c.Model().Commits) == 0 {
return self.c.ErrorMsg(self.c.Tr.NoCommitToAmend)
return errors.New(self.c.Tr.NoCommitToAmend)
}
return self.c.Helpers().AmendHelper.AmendHead()
@@ -778,7 +766,7 @@ func (self *FilesController) createStashMenu() error {
Label: self.c.Tr.StashAllChanges,
OnPress: func() error {
if !self.c.Helpers().WorkingTree.IsWorkingTreeDirty() {
return self.c.ErrorMsg(self.c.Tr.NoFilesToStash)
return errors.New(self.c.Tr.NoFilesToStash)
}
return self.handleStashSave(self.c.Git().Stash.Push, self.c.Tr.Actions.StashAllChanges)
},
@@ -788,7 +776,7 @@ func (self *FilesController) createStashMenu() error {
Label: self.c.Tr.StashAllChangesKeepIndex,
OnPress: func() error {
if !self.c.Helpers().WorkingTree.IsWorkingTreeDirty() {
return self.c.ErrorMsg(self.c.Tr.NoFilesToStash)
return errors.New(self.c.Tr.NoFilesToStash)
}
// if there are no staged files it behaves the same as Stash.Save
return self.handleStashSave(self.c.Git().Stash.StashAndKeepIndex, self.c.Tr.Actions.StashAllChangesKeepIndex)
@@ -807,7 +795,7 @@ func (self *FilesController) createStashMenu() error {
OnPress: func() error {
// there must be something in staging otherwise the current implementation mucks the stash up
if !self.c.Helpers().WorkingTree.AnyStagedFiles() {
return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash)
return errors.New(self.c.Tr.NoTrackedStagedFilesStash)
}
return self.handleStashSave(self.c.Git().Stash.SaveStagedChanges, self.c.Tr.Actions.StashStagedChanges)
},
@@ -817,7 +805,7 @@ func (self *FilesController) createStashMenu() error {
Label: self.c.Tr.StashUnstagedChanges,
OnPress: func() error {
if !self.c.Helpers().WorkingTree.IsWorkingTreeDirty() {
return self.c.ErrorMsg(self.c.Tr.NoFilesToStash)
return errors.New(self.c.Tr.NoFilesToStash)
}
if self.c.Helpers().WorkingTree.AnyStagedFiles() {
return self.handleStashSave(self.c.Git().Stash.StashUnstagedChanges, self.c.Tr.Actions.StashUnstagedChanges)
@@ -838,7 +826,7 @@ func (self *FilesController) openCopyMenu() error {
Label: self.c.Tr.CopyFileName,
OnPress: func() error {
if err := self.c.OS().CopyToClipboard(node.Name()); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.FileNameCopiedToast)
return nil
@@ -850,7 +838,7 @@ func (self *FilesController) openCopyMenu() error {
Label: self.c.Tr.CopyFilePath,
OnPress: func() error {
if err := self.c.OS().CopyToClipboard(node.Path); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.FilePathCopiedToast)
return nil
@@ -866,10 +854,10 @@ func (self *FilesController) openCopyMenu() error {
hasStaged := self.hasPathStagedChanges(node)
diff, err := self.c.Git().Diff.GetPathDiff(path, hasStaged)
if err != nil {
return self.c.Error(err)
return err
}
if err := self.c.OS().CopyToClipboard(diff); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.FileDiffCopiedToast)
return nil
@@ -891,10 +879,10 @@ func (self *FilesController) openCopyMenu() error {
hasStaged := self.c.Helpers().WorkingTree.AnyStagedFiles()
diff, err := self.c.Git().Diff.GetAllDiff(hasStaged)
if err != nil {
return self.c.Error(err)
return err
}
if err := self.c.OS().CopyToClipboard(diff); err != nil {
return self.c.Error(err)
return err
}
self.c.Toast(self.c.Tr.AllFilesDiffCopiedToast)
return nil
@@ -970,7 +958,7 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro
self.c.LogAction(action)
if err := stashFunc(stashComment); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
},
@@ -988,7 +976,7 @@ func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) e
func (self *FilesController) fetch() error {
return self.c.WithWaitingStatus(self.c.Tr.FetchingStatus, func(task gocui.Task) error {
if err := self.fetchAux(task); err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
})
@@ -999,7 +987,7 @@ func (self *FilesController) fetchAux(task gocui.Task) (err error) {
err = self.c.Git().Sync.Fetch(task)
if err != nil && strings.Contains(err.Error(), "exit status 128") {
_ = self.c.ErrorMsg(self.c.Tr.PassUnameWrong)
return errors.New(self.c.Tr.PassUnameWrong)
}
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC})
@@ -1086,7 +1074,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error {
for _, node := range selectedNodes {
if err := self.c.Git().WorkingTree.DiscardAllDirChanges(node); err != nil {
return self.c.Error(err)
return err
}
}
@@ -1114,7 +1102,7 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error {
for _, node := range selectedNodes {
if err := self.c.Git().WorkingTree.DiscardUnstagedDirChanges(node); err != nil {
return self.c.Error(err)
return err
}
}
@@ -1140,15 +1128,15 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e
file := self.c.Helpers().WorkingTree.FileForSubmodule(submodule)
if file != nil {
if err := self.c.Git().WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
return self.c.Error(err)
return err
}
}
if err := self.c.Git().Submodule.Stash(submodule); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Git().Submodule.Reset(submodule); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}})

View File

@@ -109,6 +109,8 @@ func (self *FilteringMenuAction) setFilteringAuthor(author string) error {
}
func (self *FilteringMenuAction) setFiltering() error {
self.c.Modes().Filtering.SetSelectedCommitHash(self.c.Contexts().LocalCommits.GetSelectedCommitHash())
repoState := self.c.State().GetRepoState()
if repoState.GetScreenMode() == types.SCREEN_NORMAL {
repoState.SetScreenMode(types.SCREEN_HALF)
@@ -118,8 +120,9 @@ func (self *FilteringMenuAction) setFiltering() error {
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() {
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() error {
self.c.Contexts().LocalCommits.SetSelection(0)
self.c.Contexts().LocalCommits.FocusLine()
return nil
}})
}

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"fmt"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -46,7 +47,7 @@ func (self *GitFlowController) GetKeybindings(opts types.KeybindingsOpts) []*typ
func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) error {
if !self.c.Git().Flow.GitFlowEnabled() {
return self.c.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features")
return errors.New("You need to install git-flow and enable it in this repo to use git-flow features")
}
startHandler := func(branchType string) func() error {
@@ -103,7 +104,7 @@ func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) er
func (self *GitFlowController) gitFlowFinishBranch(branchName string) error {
cmdObj, err := self.c.Git().Flow.FinishCmdObj(branchName)
if err != nil {
return self.c.Error(err)
return err
}
self.c.LogAction(self.c.Tr.Actions.GitFlowFinish)

View File

@@ -6,7 +6,6 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/status"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
type AppStatusHelper struct {
@@ -60,26 +59,20 @@ func (self appStatusHelperTask) Continue() {
// withWaitingStatus wraps a function and shows a waiting status while the function is still executing
func (self *AppStatusHelper) WithWaitingStatus(message string, f func(gocui.Task) error) {
self.c.OnWorker(func(task gocui.Task) {
self.statusMgr().WithWaitingStatus(message, self.renderAppStatus, func(waitingStatusHandle *status.WaitingStatusHandle) {
if err := f(appStatusHelperTask{task, waitingStatusHandle}); err != nil {
self.c.OnUIThread(func() error {
return self.c.Error(err)
})
}
self.c.OnWorker(func(task gocui.Task) error {
return self.statusMgr().WithWaitingStatus(message, self.renderAppStatus, func(waitingStatusHandle *status.WaitingStatusHandle) error {
return f(appStatusHelperTask{task, waitingStatusHandle})
})
})
}
func (self *AppStatusHelper) WithWaitingStatusSync(message string, f func() error) {
self.statusMgr().WithWaitingStatus(message, func() {}, func(*status.WaitingStatusHandle) {
func (self *AppStatusHelper) WithWaitingStatusSync(message string, f func() error) error {
return self.statusMgr().WithWaitingStatus(message, func() {}, func(*status.WaitingStatusHandle) error {
stop := make(chan struct{})
defer func() { close(stop) }()
self.renderAppStatusSync(stop)
if err := f(); err != nil {
_ = self.c.Error(err)
}
return f()
})
}
@@ -88,16 +81,16 @@ func (self *AppStatusHelper) HasStatus() bool {
}
func (self *AppStatusHelper) GetStatusString() string {
appStatus, _ := self.statusMgr().GetStatusString()
appStatus, _ := self.statusMgr().GetStatusString(self.c.UserConfig)
return appStatus
}
func (self *AppStatusHelper) renderAppStatus() {
self.c.OnWorker(func(_ gocui.Task) {
ticker := time.NewTicker(time.Millisecond * utils.LoaderAnimationInterval)
self.c.OnWorker(func(_ gocui.Task) error {
ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig.Gui.Spinner.Rate))
defer ticker.Stop()
for range ticker.C {
appStatus, color := self.statusMgr().GetStatusString()
appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig)
self.c.Views().AppStatus.FgColor = color
self.c.OnUIThread(func() error {
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
@@ -105,9 +98,10 @@ func (self *AppStatusHelper) renderAppStatus() {
})
if appStatus == "" {
return
break
}
}
return nil
})
}
@@ -130,7 +124,7 @@ func (self *AppStatusHelper) renderAppStatusSync(stop chan struct{}) {
for {
select {
case <-ticker.C:
appStatus, color := self.statusMgr().GetStatusString()
appStatus, color := self.statusMgr().GetStatusString(self.c.UserConfig)
self.c.Views().AppStatus.FgColor = color
self.c.SetViewContent(self.c.Views().AppStatus, appStatus)
// Redraw all views of the bottom line:

View File

@@ -19,7 +19,7 @@ func (self *BisectHelper) Reset() error {
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.ResetBisect)
if err := self.c.Git().Bisect.Reset(); err != nil {
return self.c.Error(err)
return err
}
return self.PostBisectCommandRefresh()

View File

@@ -37,7 +37,7 @@ func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName st
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
if err := self.c.Git().Remote.DeleteRemoteBranch(task, remoteName, branchName); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
})

View File

@@ -38,10 +38,10 @@ func (self *CherryPickHelper) CopyRange(commitsList []*models.Commit, context ty
return err
}
commitSet := self.getData().SelectedShaSet()
commitSet := self.getData().SelectedHashSet()
allCommitsCopied := lo.EveryBy(commitsList[startIdx:endIdx+1], func(commit *models.Commit) bool {
return commitSet.Includes(commit.Sha)
return commitSet.Includes(commit.Hash)
})
// if all selected commits are already copied, we'll uncopy them

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"path/filepath"
"strings"
"time"
@@ -167,7 +168,7 @@ func (self *CommitsHelper) HandleCommitConfirm() error {
summary, description := self.getCommitSummary(), self.getCommitDescription()
if summary == "" {
return self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr)
return errors.New(self.c.Tr.CommitWithoutMessageErr)
}
err := self.c.Contexts().CommitMessage.OnConfirm(summary, description)

View File

@@ -36,7 +36,7 @@ func (self *ConfirmationHelper) wrappedConfirmationFunction(cancel goContext.Can
if function != nil {
if err := function(); err != nil {
return self.c.Error(err)
return err
}
}
@@ -215,7 +215,7 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
confirmationView.RenderTextArea()
} else {
self.c.ResetViewOrigin(confirmationView)
self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(opts.Prompt))
self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(underlineLinks(opts.Prompt)))
}
if err := self.setKeyBindings(cancel, opts); err != nil {
@@ -228,6 +228,32 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
return self.c.PushContext(self.c.Contexts().Confirmation)
}
func underlineLinks(text string) string {
result := ""
remaining := text
for {
linkStart := strings.Index(remaining, "https://")
if linkStart == -1 {
break
}
linkEnd := strings.IndexAny(remaining[linkStart:], " \n>")
if linkEnd == -1 {
linkEnd = len(remaining)
} else {
linkEnd += linkStart
}
underlinedLink := style.AttrUnderline.Sprint(remaining[linkStart:linkEnd])
if strings.HasSuffix(underlinedLink, "\x1b[0m") {
// Replace the "all styles off" code with "underline off" code
underlinedLink = underlinedLink[:len(underlinedLink)-2] + "24m"
}
result += remaining[:linkStart] + underlinedLink
remaining = remaining[linkEnd:]
}
return result + remaining
}
func (self *ConfirmationHelper) setKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) error {
var onConfirm func() error
if opts.HandleConfirmPrompt != nil {

View File

@@ -0,0 +1,63 @@
package helpers
import (
"testing"
"github.com/gookit/color"
"github.com/stretchr/testify/assert"
"github.com/xo/terminfo"
)
func Test_underlineLinks(t *testing.T) {
scenarios := []struct {
name string
text string
expectedResult string
}{
{
name: "empty string",
text: "",
expectedResult: "",
},
{
name: "no links",
text: "abc",
expectedResult: "abc",
},
{
name: "entire string is a link",
text: "https://example.com",
expectedResult: "\x1b[4mhttps://example.com\x1b[24m",
},
{
name: "link preceeded and followed by text",
text: "bla https://example.com xyz",
expectedResult: "bla \x1b[4mhttps://example.com\x1b[24m xyz",
},
{
name: "more than one link",
text: "bla https://link1 blubb https://link2 xyz",
expectedResult: "bla \x1b[4mhttps://link1\x1b[24m blubb \x1b[4mhttps://link2\x1b[24m xyz",
},
{
name: "link in angle brackets",
text: "See <https://example.com> for details",
expectedResult: "See <\x1b[4mhttps://example.com\x1b[24m> for details",
},
{
name: "link followed by newline",
text: "URL: https://example.com\nNext line",
expectedResult: "URL: \x1b[4mhttps://example.com\x1b[24m\nNext line",
},
}
oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelMillions)
defer color.ForceSetColorLevel(oldColorLevel)
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
result := underlineLinks(s.text)
assert.Equal(t, s.expectedResult, result)
})
}
}

View File

@@ -85,7 +85,7 @@ func (self *FilesHelper) OpenFile(filename string) error {
}
self.c.LogAction(self.c.Tr.Actions.OpenFile)
if err := self.c.OS().OpenFile(absPath); err != nil {
return self.c.Error(err)
return err
}
return nil
}

View File

@@ -1,6 +1,8 @@
package helpers
import (
"errors"
"fmt"
"regexp"
"strings"
"sync"
@@ -36,33 +38,33 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
return err
}
if diff == "" {
return self.c.ErrorMsg(self.c.Tr.NoChangedFiles)
return errors.New(self.c.Tr.NoChangedFiles)
}
deletedLineInfos, hasHunksWithOnlyAddedLines := self.parseDiff(diff)
if len(deletedLineInfos) == 0 {
return self.c.ErrorMsg(self.c.Tr.NoDeletedLinesInDiff)
return errors.New(self.c.Tr.NoDeletedLinesInDiff)
}
shas := self.blameDeletedLines(deletedLineInfos)
hashes := self.blameDeletedLines(deletedLineInfos)
if len(shas) == 0 {
if len(hashes) == 0 {
// This should never happen
return self.c.ErrorMsg(self.c.Tr.NoBaseCommitsFound)
return errors.New(self.c.Tr.NoBaseCommitsFound)
}
if len(shas) > 1 {
subjects, err := self.c.Git().Commit.GetShasAndCommitMessagesFirstLine(shas)
if len(hashes) > 1 {
subjects, err := self.c.Git().Commit.GetHashesAndCommitMessagesFirstLine(hashes)
if err != nil {
return err
}
message := lo.Ternary(hasStagedChanges,
self.c.Tr.MultipleBaseCommitsFoundStaged,
self.c.Tr.MultipleBaseCommitsFoundUnstaged)
return self.c.ErrorMsg(message + "\n\n" + subjects)
return fmt.Errorf("%s\n\n%s", message, subjects)
}
commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool {
return commit.Sha == shas[0]
return commit.Hash == hashes[0]
})
if !ok {
commits := self.c.Model().Commits
@@ -70,13 +72,13 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
// If the commit is not found, it's most likely because it's already
// merged, and more than 300 commits away. Check if the last known
// commit is already merged; if so, show the "already merged" error.
return self.c.ErrorMsg(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
return errors.New(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
}
// If we get here, the current branch must have more then 300 commits. Unlikely...
return self.c.ErrorMsg(self.c.Tr.BaseCommitIsNotInCurrentView)
return errors.New(self.c.Tr.BaseCommitIsNotInCurrentView)
}
if commit.Status == models.StatusMerged {
return self.c.ErrorMsg(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
return errors.New(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
}
doIt := func() error {
@@ -164,7 +166,7 @@ func (self *FixupHelper) parseDiff(diff string) ([]*deletedLineInfo, bool) {
// returns the list of commit hashes that introduced the lines which have now been deleted
func (self *FixupHelper) blameDeletedLines(deletedLineInfos []*deletedLineInfo) []string {
var wg sync.WaitGroup
shaChan := make(chan string)
hashChan := make(chan string)
for _, info := range deletedLineInfos {
wg.Add(1)
@@ -178,19 +180,19 @@ func (self *FixupHelper) blameDeletedLines(deletedLineInfos []*deletedLineInfo)
}
blameLines := strings.Split(strings.TrimSuffix(blameOutput, "\n"), "\n")
for _, line := range blameLines {
shaChan <- strings.Split(line, " ")[0]
hashChan <- strings.Split(line, " ")[0]
}
}(info)
}
go func() {
wg.Wait()
close(shaChan)
close(hashChan)
}()
result := set.New[string]()
for sha := range shaChan {
result.Add(sha)
for hash := range hashChan {
result.Add(hash)
}
return result.ToSlice()

View File

@@ -45,10 +45,8 @@ func (self *GpgHelper) runAndStream(cmdObj oscommands.ICmdObj, waitingStatus str
return self.c.WithWaitingStatus(waitingStatus, func(gocui.Task) error {
if err := cmdObj.StreamOutput().Run(); err != nil {
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
return self.c.Error(
fmt.Errorf(
self.c.Tr.GitCommandFailed, self.c.UserConfig.Keybinding.Universal.ExtrasMenu,
),
return fmt.Errorf(
self.c.Tr.GitCommandFailed, self.c.UserConfig.Keybinding.Universal.ExtrasMenu,
)
}

View File

@@ -8,7 +8,7 @@ import (
type IHostHelper interface {
GetPullRequestURL(from string, to string) (string, error)
GetCommitURL(commitSha string) (string, error)
GetCommitURL(commitHash string) (string, error)
}
type HostHelper struct {
@@ -31,12 +31,12 @@ func (self *HostHelper) GetPullRequestURL(from string, to string) (string, error
return mgr.GetPullRequestURL(from, to)
}
func (self *HostHelper) GetCommitURL(commitSha string) (string, error) {
func (self *HostHelper) GetCommitURL(commitHash string) (string, error) {
mgr, err := self.getHostingServiceMgr()
if err != nil {
return "", err
}
return mgr.GetCommitURL(commitSha)
return mgr.GetCommitURL(commitHash)
}
// getting this on every request rather than storing it in state in case our remoteURL changes

View File

@@ -68,17 +68,11 @@ func (self *InlineStatusHelper) WithInlineStatus(opts InlineStatusOpts, f func(g
view := context.GetView()
visible := view.Visible && self.windowHelper.TopViewInWindow(context.GetWindowName(), false) == view
if visible && context.IsItemVisible(opts.Item) {
self.c.OnWorker(func(task gocui.Task) {
self.c.OnWorker(func(task gocui.Task) error {
self.start(opts)
defer self.stop(opts)
err := f(inlineStatusHelperTask{task, self, opts})
if err != nil {
self.c.OnUIThread(func() error {
return self.c.Error(err)
})
}
self.stop(opts)
return f(inlineStatusHelperTask{task, self, opts})
})
} else {
message := presentation.ItemOperationToString(opts.Operation, self.c.Tr)
@@ -105,7 +99,7 @@ func (self *InlineStatusHelper) start(opts InlineStatusOpts) {
self.contextsWithInlineStatus[opts.ContextKey] = info
go utils.Safe(func() {
ticker := time.NewTicker(time.Millisecond * utils.LoaderAnimationInterval)
ticker := time.NewTicker(time.Millisecond * time.Duration(self.c.UserConfig.Gui.Spinner.Rate))
defer ticker.Stop()
outer:
for {
@@ -131,12 +125,28 @@ func (self *InlineStatusHelper) stop(opts InlineStatusOpts) {
info.stop <- struct{}{}
delete(self.contextsWithInlineStatus, opts.ContextKey)
}
}
self.mutex.Unlock()
self.c.State().ClearItemOperation(opts.Item)
// When recording a demo we need to re-render the context again here to
// remove the inline status. In normal usage we don't want to do this
// because in the case of pushing a branch this would first reveal the ↑3↓7
// status from before the push for a brief moment, to be replaced by a green
// checkmark a moment later when the async refresh is done. This looks
// jarring, so normally we rely on the async refresh to redraw with the
// status removed. (In some rare cases, where there's no refresh at all, we
// need to redraw manually in the controller; see TagsController.push() for
// an example.)
//
// In demos, however, we turn all async refreshes into sync ones, because
// this looks better in demos. In this case the refresh happens while the
// status is still set, so we need to render again after removing it.
if self.c.InDemo() {
self.renderContext(opts.ContextKey)
}
}
func (self *InlineStatusHelper) renderContext(contextKey types.ContextKey) {

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -78,7 +79,7 @@ func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error {
status := self.c.Git().Status.WorkingTreeState()
if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING {
return self.c.ErrorMsg(self.c.Tr.NotMergingOrRebasing)
return errors.New(self.c.Tr.NotMergingOrRebasing)
}
self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command))
@@ -169,9 +170,9 @@ func (self *MergeAndRebaseHelper) CheckForConflicts(result error) error {
if isMergeConflictErr(result.Error()) {
return self.PromptForConflictHandling()
} else {
return self.c.ErrorMsg(result.Error())
}
return result
}
func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
@@ -241,7 +242,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(task gocui.Task) error {
baseCommit := self.c.Modes().MarkedBaseCommit.GetSha()
baseCommit := self.c.Modes().MarkedBaseCommit.GetHash()
var err error
if baseCommit != "" {
err = self.c.Git().Rebase.RebaseBranchFromBaseCommit(ref, baseCommit)
@@ -262,7 +263,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
Tooltip: self.c.Tr.InteractiveRebaseTooltip,
OnPress: func() error {
self.c.LogAction(self.c.Tr.Actions.RebaseBranch)
baseCommit := self.c.Modes().MarkedBaseCommit.GetSha()
baseCommit := self.c.Modes().MarkedBaseCommit.GetHash()
var err error
if baseCommit != "" {
err = self.c.Git().Rebase.EditRebaseFromBaseCommit(ref, baseCommit)
@@ -281,7 +282,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
}
title := utils.ResolvePlaceholderString(
lo.Ternary(self.c.Modes().MarkedBaseCommit.GetSha() != "",
lo.Ternary(self.c.Modes().MarkedBaseCommit.GetHash() != "",
self.c.Tr.RebasingFromBaseCommitTitle,
self.c.Tr.RebasingTitle),
map[string]string{
@@ -298,11 +299,11 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error {
func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) error {
if self.c.Git().Branch.IsHeadDetached() {
return self.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on")
return errors.New("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on")
}
checkedOutBranchName := self.refsHelper.GetCheckedOutRef().Name
if checkedOutBranchName == refName {
return self.c.ErrorMsg(self.c.Tr.CantMergeBranchIntoItself)
return errors.New(self.c.Tr.CantMergeBranchIntoItself)
}
prompt := utils.ResolvePlaceholderString(
self.c.Tr.ConfirmMerge,

View File

@@ -129,7 +129,7 @@ func (self *MergeConflictsHelper) RefreshMergeState() error {
hasConflicts, err := self.SetConflictsAndRender(self.c.Contexts().MergeConflicts.GetState().GetPath())
if err != nil {
return self.c.Error(err)
return err
}
if !hasConflicts {

View File

@@ -163,12 +163,26 @@ func (self *ModeHelper) ExitFilterMode() error {
}
func (self *ModeHelper) ClearFiltering() error {
selectedCommitHash := self.c.Contexts().LocalCommits.GetSelectedCommitHash()
self.c.Modes().Filtering.Reset()
if self.c.State().GetRepoState().GetScreenMode() == types.SCREEN_HALF {
self.c.State().GetRepoState().SetScreenMode(types.SCREEN_NORMAL)
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}})
return self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.COMMITS},
Then: func() error {
// Find the commit that was last selected in filtering mode, and select it again after refreshing
if !self.c.Contexts().LocalCommits.SelectCommitByHash(selectedCommitHash) {
// If we couldn't find it (either because no commit was selected
// in filtering mode, or because the commit is outside the
// initial 300 range), go back to the commit that was selected
// before we entered filtering
self.c.Contexts().LocalCommits.SelectCommitByHash(self.c.Modes().Filtering.GetSelectedCommitHash())
}
return nil
},
})
}
func (self *ModeHelper) SetSuppressRebasingMode(value bool) {

View File

@@ -1,6 +1,8 @@
package helpers
import (
"errors"
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
"github.com/jesseduffield/lazygit/pkg/gui/types"
@@ -24,7 +26,7 @@ func NewPatchBuildingHelper(
func (self *PatchBuildingHelper) ValidateNormalWorkingTreeState() (bool, error) {
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
return false, self.c.ErrorMsg(self.c.Tr.CantPatchWhileRebasingError)
return false, errors.New(self.c.Tr.CantPatchWhileRebasingError)
}
return true, nil
}

View File

@@ -76,7 +76,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
)
}
f := func() {
f := func() error {
var scopeSet *set.Set[types.RefreshableView]
if len(options.Scope) == 0 {
// not refreshing staging/patch-building unless explicitly requested because we only need
@@ -104,8 +104,9 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
// everything happens fast and it's better to have everything update
// in the one frame
if !self.c.InDemo() && options.Mode == types.ASYNC {
self.c.OnWorker(func(t gocui.Task) {
self.c.OnWorker(func(t gocui.Task) error {
f()
return nil
})
} else {
wg.Add(1)
@@ -187,20 +188,22 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
wg.Wait()
if options.Then != nil {
options.Then()
if err := options.Then(); err != nil {
return err
}
}
return nil
}
if options.Mode == types.BLOCK_UI {
self.c.OnUIThread(func() error {
f()
return nil
return f()
})
} else {
f()
return nil
}
return nil
return f()
}
func getScopeNames(scopes []types.RefreshableView) []string {
@@ -246,10 +249,11 @@ func getModeName(mode types.RefreshMode) string {
func (self *RefreshHelper) refreshReflogCommitsConsideringStartup() {
switch self.c.State().GetRepoState().GetStartupStage() {
case types.INITIAL:
self.c.OnWorker(func(_ gocui.Task) {
self.c.OnWorker(func(_ gocui.Task) error {
_ = self.refreshReflogCommits()
self.refreshBranches(false, true)
self.c.State().GetRepoState().SetStartupStage(types.COMPLETE)
return nil
})
case types.COMPLETE:
@@ -267,7 +271,7 @@ func (self *RefreshHelper) refreshCommitsAndCommitFiles() {
_ = self.refreshCommitsWithLimit()
ctx, ok := self.c.Contexts().CommitFiles.GetParentContext()
if ok && ctx.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY {
// This makes sense when we've e.g. just amended a commit, meaning we get a new commit SHA at the same position.
// This makes sense when we've e.g. just amended a commit, meaning we get a new commit hash at the same position.
// However if we've just added a brand new commit, it pushes the list down by one and so we would end up
// showing the contents of a different commit than the one we initially entered.
// Ideally we would know when to refresh the commit files context and when not to,
@@ -290,16 +294,16 @@ func (self *RefreshHelper) determineCheckedOutBranchName() string {
return strings.TrimPrefix(rebasedBranch, "refs/heads/")
}
if bisectInfo := self.c.Git().Bisect.GetInfo(); bisectInfo.Bisecting() && bisectInfo.GetStartSha() != "" {
if bisectInfo := self.c.Git().Bisect.GetInfo(); bisectInfo.Bisecting() && bisectInfo.GetStartHash() != "" {
// Likewise, when we're bisecting we're on a detached head as well. In
// this case we read the branch name from the ".git/BISECT_START" file.
return bisectInfo.GetStartSha()
return bisectInfo.GetStartHash()
}
// In all other cases, get the branch name by asking git what branch is
// checked out. Note that if we're on a detached head (for reasons other
// than rebasing or bisecting, i.e. it was explicitly checked out), then
// this will return its sha.
// this will return its hash.
if branchName, err := self.c.Git().Branch.CurrentBranchName(); err == nil {
return branchName
}
@@ -381,7 +385,7 @@ func (self *RefreshHelper) refreshCommitFilesContext() error {
files, err := self.c.Git().Loaders.CommitFileLoader.GetFilesInDiff(from, to, reverse)
if err != nil {
return self.c.Error(err)
return err
}
self.c.Model().CommitFiles = files
self.c.Contexts().CommitFiles.CommitFileTreeViewModel.SetTree()
@@ -406,7 +410,7 @@ func (self *RefreshHelper) refreshRebaseCommits() error {
func (self *RefreshHelper) refreshTags() error {
tags, err := self.c.Git().Loaders.TagLoader.GetTags()
if err != nil {
return self.c.Error(err)
return err
}
self.c.Model().Tags = tags
@@ -448,7 +452,7 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
branches, err := self.c.Git().Loaders.BranchLoader.Load(reflogCommits)
if err != nil {
_ = self.c.Error(err)
self.c.Log.Error(err)
}
self.c.Model().Branches = branches
@@ -543,7 +547,7 @@ func (self *RefreshHelper) refreshStateFiles() error {
if len(pathsToStage) > 0 {
self.c.LogAction(self.c.Tr.Actions.StageResolvedFiles)
if err := self.c.Git().WorkingTree.StageFiles(pathsToStage); err != nil {
return self.c.Error(err)
return err
}
}
@@ -603,7 +607,7 @@ func (self *RefreshHelper) refreshReflogCommits() error {
commits, onlyObtainedNewReflogCommits, err := self.c.Git().Loaders.ReflogCommitLoader.
GetReflogCommits(lastReflogCommit, filterPath, filterAuthor)
if err != nil {
return self.c.Error(err)
return err
}
if onlyObtainedNewReflogCommits {
@@ -634,7 +638,7 @@ func (self *RefreshHelper) refreshRemotes() error {
remotes, err := self.c.Git().Loaders.RemoteLoader.GetRemotes()
if err != nil {
return self.c.Error(err)
return err
}
self.c.Model().Remotes = remotes
@@ -706,7 +710,7 @@ func (self *RefreshHelper) refreshStatus() {
repoName := self.c.Git().RepoPaths.RepoName()
status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr)
status := presentation.FormatStatus(repoName, currentBranch, types.ItemOperationNone, linkedWorktreeName, workingTreeState, self.c.Tr, self.c.UserConfig)
self.c.SetViewContent(self.c.Views().Status, status)
}
@@ -721,10 +725,10 @@ func (self *RefreshHelper) refForLog() string {
// need to see if our bisect's current commit is reachable from our 'new' ref.
if bisectInfo.Bisecting() && !self.c.Git().Bisect.ReachableFromStart(bisectInfo) {
return bisectInfo.GetNewSha()
return bisectInfo.GetNewHash()
}
return bisectInfo.GetStartSha()
return bisectInfo.GetStartHash()
}
func (self *RefreshHelper) refreshView(context types.Context) error {

View File

@@ -69,10 +69,10 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
Prompt: self.c.Tr.AutoStashPrompt,
HandleConfirm: func() error {
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + ref); err != nil {
return self.c.Error(err)
return err
}
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
return self.c.Error(err)
return err
}
onSuccess()
@@ -80,16 +80,14 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
if err := self.c.Refresh(refreshOptions); err != nil {
return err
}
return self.c.Error(err)
return err
}
return self.c.Refresh(refreshOptions)
},
})
}
if err := self.c.Error(err); err != nil {
return err
}
return err
}
onSuccess()
@@ -142,7 +140,7 @@ func (self *RefsHelper) CheckoutRemoteBranch(fullBranchName string, localBranchN
// "git checkout -b", but we want to benefit from all the
// nice features of the CheckoutRef function.
if err := self.c.Git().Branch.CreateWithUpstream(localBranchName, fullBranchName); err != nil {
return self.c.Error(err)
return err
}
// Do a sync refresh to make sure the new branch is visible,
// so that we see an inline status when checking it out
@@ -176,7 +174,7 @@ func (self *RefsHelper) GetCheckedOutRef() *models.Branch {
func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string) error {
if err := self.c.Git().Commit.ResetToCommit(ref, strength, envVars); err != nil {
return self.c.Error(err)
return err
}
self.c.Contexts().LocalCommits.SetSelection(0)

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -62,8 +63,8 @@ func (self *ReposHelper) getCurrentBranch(path string) string {
// is a branch
branchDisplay = strings.TrimPrefix(content, refsPrefix)
} else {
// detached HEAD state, displaying short SHA
branchDisplay = utils.ShortSha(content)
// detached HEAD state, displaying short hash
branchDisplay = utils.ShortHash(content)
}
return branchDisplay, nil
}
@@ -156,7 +157,7 @@ func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey
if err := os.Chdir(path); err != nil {
if os.IsNotExist(err) {
return self.c.ErrorMsg(errMsg)
return errors.New(errMsg)
}
return err
}

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"fmt"
"strings"
@@ -39,7 +40,7 @@ func (self *SnakeHelper) renderSnakeGame(cells [][]snake.CellType, alive bool) {
view := self.c.Views().Snake
if !alive {
_ = self.c.ErrorMsg(self.c.Tr.YouDied)
self.c.OnUIThread(func() error { return errors.New(self.c.Tr.YouDied) })
return
}

View File

@@ -25,12 +25,12 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
if description != "" {
self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
if err := self.c.Git().Tag.CreateAnnotated(tagName, ref, description, force); err != nil {
return self.c.Error(err)
return err
}
} else {
self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
if err := self.c.Git().Tag.CreateLightweight(tagName, ref, force); err != nil {
return self.c.Error(err)
return err
}
}

View File

@@ -1,6 +1,8 @@
package helpers
import (
"errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/updates"
@@ -41,10 +43,10 @@ func (self *UpdateHelper) CheckForUpdateInForeground() error {
return self.c.WithWaitingStatus(self.c.Tr.CheckingForUpdates, func(gocui.Task) error {
self.updater.CheckForNewUpdate(func(newVersion string, err error) error {
if err != nil {
return self.c.Error(err)
return err
}
if newVersion == "" {
return self.c.ErrorMsg(self.c.Tr.FailedToRetrieveLatestVersionErr)
return errors.New(self.c.Tr.FailedToRetrieveLatestVersionErr)
}
return self.showUpdatePrompt(newVersion)
}, true)
@@ -71,7 +73,7 @@ func (self *UpdateHelper) onUpdateFinish(err error) error {
"errMessage": err.Error(),
},
)
return self.c.ErrorMsg(errMessage)
return errors.New(errMessage)
}
return self.c.Alert(self.c.Tr.UpdateCompletedTitle, self.c.Tr.UpdateCompleted)
})

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"fmt"
"regexp"
@@ -137,7 +138,7 @@ func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix
if skipHookPrefix == "" {
return self.c.ErrorMsg(self.c.Tr.SkipHookPrefixNotConfigured)
return errors.New(self.c.Tr.SkipHookPrefixNotConfigured)
}
return self.HandleCommitPressWithMessage(skipHookPrefix)
@@ -153,7 +154,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
prefixReplace := commitPrefixConfig.Replace
rgx, err := regexp.Compile(prefixPattern)
if err != nil {
return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.CommitPrefixPatternError, err.Error()))
return fmt.Errorf("%s: %s", self.c.Tr.CommitPrefixPatternError, err.Error())
}
prefix := rgx.ReplaceAllString(self.refHelper.GetCheckedOutRef().Name, prefixReplace)
message = prefix
@@ -165,11 +166,11 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
func (self *WorkingTreeHelper) WithEnsureCommitableFiles(handler func() error) error {
if err := self.prepareFilesForCommit(); err != nil {
return self.c.Error(err)
return err
}
if len(self.c.Model().Files) == 0 {
return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle)
return errors.New(self.c.Tr.NoFilesStagedTitle)
}
if !self.AnyStagedFiles() {
@@ -186,10 +187,10 @@ func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) erro
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.StageAllFiles)
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
return self.c.Error(err)
return err
}
if err := self.syncRefresh(); err != nil {
return self.c.Error(err)
return err
}
return retry()

View File

@@ -1,6 +1,7 @@
package helpers
import (
"errors"
"strings"
"github.com/jesseduffield/gocui"
@@ -139,7 +140,7 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo
Title: self.c.Tr.NewBranchName,
HandleConfirm: func(branchName string) error {
if branchName == "" {
return self.c.ErrorMsg(self.c.Tr.BranchNameCannotBeBlank)
return errors.New(self.c.Tr.BranchNameCannotBeBlank)
}
opts.Branch = branchName
@@ -154,7 +155,7 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo
func (self *WorktreeHelper) Switch(worktree *models.Worktree, contextKey types.ContextKey) error {
if worktree.IsCurrent {
return self.c.ErrorMsg(self.c.Tr.AlreadyInWorktree)
return errors.New(self.c.Tr.AlreadyInWorktree)
}
self.c.LogAction(self.c.Tr.SwitchToWorktree)
@@ -186,13 +187,13 @@ func (self *WorktreeHelper) Remove(worktree *models.Worktree, force bool) error
if err := self.c.Git().Worktree.Delete(worktree.Path, force); err != nil {
errMessage := err.Error()
if !strings.Contains(errMessage, "--force") {
return self.c.Error(err)
return err
}
if !force {
return self.Remove(worktree, true)
}
return self.c.ErrorMsg(errMessage)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
})
@@ -206,7 +207,7 @@ func (self *WorktreeHelper) Detach(worktree *models.Worktree) error {
err := self.c.Git().Worktree.Detach(worktree.Path)
if err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
})

View File

@@ -1,6 +1,10 @@
package controllers
import "github.com/jesseduffield/lazygit/pkg/gui/types"
import (
"errors"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
// Embed this into your list controller to get some convenience methods for
// ensuring a single item is selected, etc.
@@ -106,7 +110,7 @@ func (self *ListControllerTrait[T]) withItem(callback func(T) error) func() erro
var zeroValue T
commit := self.getSelectedItem()
if commit == zeroValue {
return self.c.ErrorMsg(self.c.Tr.NoItemSelected)
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(commit)
@@ -117,7 +121,7 @@ func (self *ListControllerTrait[T]) withItems(callback func([]T) error) func() e
return func() error {
items, _, _ := self.getSelectedItems()
if len(items) == 0 {
return self.c.ErrorMsg(self.c.Tr.NoItemSelected)
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(items)
@@ -129,7 +133,7 @@ func (self *ListControllerTrait[T]) withItemsRange(callback func([]T, int, int)
return func() error {
items, startIdx, endIdx := self.getSelectedItems()
if len(items) == 0 {
return self.c.ErrorMsg(self.c.Tr.NoItemSelected)
return errors.New(self.c.Tr.NoItemSelected)
}
return callback(items, startIdx, endIdx)

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"github.com/fsmiamoto/git-todo-parser/todo"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
@@ -16,6 +15,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo"
)
// after selecting the 200th commit, we'll load in all the rest
@@ -285,7 +285,7 @@ func (self *LocalCommitsController) GetOnRenderToMain() func() error {
"ref": strings.TrimPrefix(commit.Name, "refs/heads/"),
}))
} else {
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Sha, self.c.Modes().Filtering.GetPath())
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Hash, self.c.Modes().Filtering.GetPath())
task = types.NewRunPtyTask(cmdObj.GetCmd())
}
@@ -350,9 +350,9 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
}
func (self *LocalCommitsController) reword(commit *models.Commit) error {
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Sha)
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
@@ -399,7 +399,7 @@ func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepat
func (self *LocalCommitsController) handleReword(summary string, description string) error {
err := self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
if err != nil {
return self.c.Error(err)
return err
}
self.c.Helpers().Commits.OnCommitSuccess()
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
@@ -416,7 +416,7 @@ func (self *LocalCommitsController) doRewordEditor() error {
self.c.Model().Commits, self.context().GetSelectedLineIdx(),
)
if err != nil {
return self.c.Error(err)
return err
}
if subProcess != nil {
return self.c.RunSubprocessAndRefresh(subProcess)
@@ -457,9 +457,9 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
}
if selectedIdx > rangeStartIdx {
selectedIdx = utils.Max(selectedIdx-len(updateRefTodos), rangeStartIdx)
selectedIdx = max(selectedIdx-len(updateRefTodos), rangeStartIdx)
} else {
rangeStartIdx = utils.Max(rangeStartIdx-len(updateRefTodos), selectedIdx)
rangeStartIdx = max(rangeStartIdx-len(updateRefTodos), selectedIdx)
}
self.context().SetSelectionRangeAndMode(selectedIdx, rangeStartIdx, rangeSelectMode)
@@ -495,7 +495,7 @@ func (self *LocalCommitsController) edit(selectedCommits []*models.Commit) error
func (self *LocalCommitsController) quickStartInteractiveRebase() error {
commitToEdit, err := self.findCommitForQuickStartInteractiveRebase()
if err != nil {
return self.c.Error(err)
return err
}
return self.startInteractiveRebaseWithEdit([]*models.Commit{commitToEdit})
@@ -508,23 +508,23 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
self.c.LogAction(self.c.Tr.Actions.EditCommit)
selectedIdx, rangeStartIdx, rangeSelectMode := self.context().GetSelectionRangeAndMode()
commits := self.c.Model().Commits
selectedSha := commits[selectedIdx].Sha
rangeStartSha := commits[rangeStartIdx].Sha
err := self.c.Git().Rebase.EditRebase(commitsToEdit[len(commitsToEdit)-1].Sha)
selectedHash := commits[selectedIdx].Hash
rangeStartHash := commits[rangeStartIdx].Hash
err := self.c.Git().Rebase.EditRebase(commitsToEdit[len(commitsToEdit)-1].Hash)
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
err,
types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() {
types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() error {
todos := make([]*models.Commit, 0, len(commitsToEdit)-1)
for _, c := range commitsToEdit[:len(commitsToEdit)-1] {
// Merge commits can't be set to "edit", so just skip them
if !c.IsMerge() {
todos = append(todos, &models.Commit{Sha: c.Sha, Action: todo.Pick})
todos = append(todos, &models.Commit{Hash: c.Hash, Action: todo.Pick})
}
}
if len(todos) > 0 {
err := self.updateTodos(todo.Edit, todos)
if err != nil {
_ = self.c.Error(err)
return err
}
}
@@ -532,14 +532,15 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
// new lines can be added for update-ref commands in the TODO file, due to
// stacked branches. So the selected commits may be in different positions in the list.
_, newSelectedIdx, ok1 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
return c.Sha == selectedSha
return c.Hash == selectedHash
})
_, newRangeStartIdx, ok2 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
return c.Sha == rangeStartSha
return c.Hash == rangeStartHash
})
if ok1 && ok2 {
self.context().SetSelectionRangeAndMode(newSelectedIdx, newRangeStartIdx, rangeSelectMode)
}
return nil
}})
})
}
@@ -587,7 +588,7 @@ func (self *LocalCommitsController) interactiveRebase(action todo.TodoCommand, s
// begin a rebase. It then updates the todo file with that action
func (self *LocalCommitsController) updateTodos(action todo.TodoCommand, selectedCommits []*models.Commit) error {
if err := self.c.Git().Rebase.EditRebaseTodo(selectedCommits, action); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{
@@ -620,7 +621,7 @@ func (self *LocalCommitsController) isRebasing() bool {
func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
if self.isRebasing() {
if err := self.c.Git().Rebase.MoveTodosDown(selectedCommits); err != nil {
return self.c.Error(err)
return err
}
self.context().MoveSelection(1)
@@ -643,7 +644,7 @@ func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, s
func (self *LocalCommitsController) moveUp(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
if self.isRebasing() {
if err := self.c.Git().Rebase.MoveTodosUp(selectedCommits); err != nil {
return self.c.Error(err)
return err
}
self.context().MoveSelection(-1)
@@ -733,7 +734,7 @@ func (self *LocalCommitsController) resetAuthor() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.ResetCommitAuthor)
if err := self.c.Git().Rebase.ResetCommitAuthor(self.c.Model().Commits, self.context().GetSelectedLineIdx()); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
@@ -748,7 +749,7 @@ func (self *LocalCommitsController) setAuthor() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SetCommitAuthor)
if err := self.c.Git().Rebase.SetCommitAuthor(self.c.Model().Commits, self.context().GetSelectedLineIdx(), value); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
@@ -765,7 +766,7 @@ func (self *LocalCommitsController) addCoAuthor() error {
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.AddCommitCoAuthor)
if err := self.c.Git().Rebase.AddCommitCoAuthor(self.c.Model().Commits, self.context().GetSelectedLineIdx(), value); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
})
@@ -782,12 +783,12 @@ func (self *LocalCommitsController) revert(commit *models.Commit) error {
Prompt: utils.ResolvePlaceholderString(
self.c.Tr.ConfirmRevertCommit,
map[string]string{
"selectedCommit": commit.ShortSha(),
"selectedCommit": commit.ShortHash(),
}),
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RevertCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.RevertingStatus, func() error {
if err := self.c.Git().Commit.Revert(commit.Sha); err != nil {
if err := self.c.Git().Commit.Revert(commit.Hash); err != nil {
return err
}
return self.afterRevertCommit()
@@ -799,20 +800,20 @@ func (self *LocalCommitsController) revert(commit *models.Commit) error {
func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.Commit) error {
menuItems := make([]*types.MenuItem, len(commit.Parents))
for i, parentSha := range commit.Parents {
for i, parentHash := range commit.Parents {
i := i
message, err := self.c.Git().Commit.GetCommitMessageFirstLine(parentSha)
message, err := self.c.Git().Commit.GetCommitMessageFirstLine(parentHash)
if err != nil {
return self.c.Error(err)
return err
}
menuItems[i] = &types.MenuItem{
Label: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message),
Label: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentHash, 8), message),
OnPress: func() error {
parentNumber := i + 1
self.c.LogAction(self.c.Tr.Actions.RevertCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.RevertingStatus, func() error {
if err := self.c.Git().Commit.RevertMerge(commit.Sha, parentNumber); err != nil {
if err := self.c.Git().Commit.RevertMerge(commit.Hash, parentNumber); err != nil {
return err
}
return self.afterRevertCommit()
@@ -850,8 +851,8 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
return self.c.Helpers().WorkingTree.WithEnsureCommitableFiles(func() error {
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.CreatingFixupCommitStatus, func() error {
if err := self.c.Git().Commit.CreateFixupCommit(commit.Sha); err != nil {
return self.c.Error(err)
if err := self.c.Git().Commit.CreateFixupCommit(commit.Hash); err != nil {
return err
}
self.context().MoveSelectedLine(1)
@@ -884,9 +885,9 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
}
func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, includeFileChanges bool) error {
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Sha)
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Hash)
if err != nil {
return self.c.Error(err)
return err
}
if self.c.UserConfig.Git.Commit.AutoWrapCommitMessage {
commitMessage = helpers.TryRemoveHardLineBreaks(commitMessage, self.c.UserConfig.Git.Commit.AutoWrapWidth)
@@ -903,7 +904,7 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.CreatingFixupCommitStatus, func() error {
if err := self.c.Git().Commit.CreateAmendCommit(originalSubject, summary, description, includeFileChanges); err != nil {
return self.c.Error(err)
return err
}
self.context().MoveSelectedLine(1)
@@ -944,7 +945,7 @@ func (self *LocalCommitsController) squashAllFixupsAboveSelectedCommit(commit *m
func (self *LocalCommitsController) squashAllFixupsInCurrentBranch() error {
commit, rebaseStartIdx, err := self.findCommitForSquashFixupsInCurrentBranch()
if err != nil {
return self.c.Error(err)
return err
}
return self.squashFixupsImpl(commit, rebaseStartIdx)
@@ -1024,7 +1025,7 @@ func isFixupCommit(subject string) (string, bool) {
}
func (self *LocalCommitsController) createTag(commit *models.Commit) error {
return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Sha, func() {})
return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Hash, func() {})
}
func (self *LocalCommitsController) openSearch() error {
@@ -1153,10 +1154,8 @@ func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
context := self.context()
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)
self.c.OnWorker(func(_ gocui.Task) {
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}); err != nil {
_ = self.c.Error(err)
}
self.c.OnWorker(func(_ gocui.Task) error {
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}})
})
}
@@ -1181,11 +1180,11 @@ func (self *LocalCommitsController) canPaste() *types.DisabledReason {
}
func (self *LocalCommitsController) markAsBaseCommit(commit *models.Commit) error {
if commit.Sha == self.c.Modes().MarkedBaseCommit.GetSha() {
if commit.Hash == self.c.Modes().MarkedBaseCommit.GetHash() {
// Reset when invoking it again on the marked commit
self.c.Modes().MarkedBaseCommit.SetSha("")
self.c.Modes().MarkedBaseCommit.SetHash("")
} else {
self.c.Modes().MarkedBaseCommit.SetSha(commit.Sha)
self.c.Modes().MarkedBaseCommit.SetHash(commit.Hash)
}
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
}

View File

@@ -286,7 +286,7 @@ func (self *PatchExplorerController) CopySelectedToClipboard() error {
self.c.LogAction(self.c.Tr.Actions.CopySelectedTextToClipboard)
if err := self.c.OS().CopyToClipboard(selected); err != nil {
return self.c.Error(err)
return err
}
return nil

View File

@@ -45,7 +45,7 @@ func (self *ReflogCommitsController) GetOnRenderToMain() func() error {
if commit == nil {
task = types.NewRenderStringTask("No reflog history")
} else {
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Sha, self.c.Modes().Filtering.GetPath())
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Hash, self.c.Modes().Filtering.GetPath())
task = types.NewRunPtyTask(cmdObj.GetCmd())
}

View File

@@ -169,7 +169,7 @@ func (self *RemoteBranchesController) setAsUpstream(selectedBranch *models.Remot
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.SetBranchUpstream)
if err := self.c.Git().Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})

View File

@@ -179,7 +179,7 @@ func (self *RemotesController) remove(remote *models.Remote) error {
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RemoveRemote)
if err := self.c.Git().Remote.RemoveRemote(remote.Name); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
@@ -202,7 +202,7 @@ func (self *RemotesController) edit(remote *models.Remote) error {
if updatedRemoteName != remote.Name {
self.c.LogAction(self.c.Tr.Actions.UpdateRemote)
if err := self.c.Git().Remote.RenameRemote(remote.Name, updatedRemoteName); err != nil {
return self.c.Error(err)
return err
}
}
@@ -225,7 +225,7 @@ func (self *RemotesController) edit(remote *models.Remote) error {
HandleConfirm: func(updatedRemoteUrl string) error {
self.c.LogAction(self.c.Tr.Actions.UpdateRemote)
if err := self.c.Git().Remote.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
},
@@ -238,7 +238,7 @@ func (self *RemotesController) fetch(remote *models.Remote) error {
return self.c.WithInlineStatus(remote, types.ItemOperationFetching, context.REMOTES_CONTEXT_KEY, func(task gocui.Task) error {
err := self.c.Git().Sync.FetchRemote(task, remote.Name)
if err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{

View File

@@ -3,7 +3,6 @@ package controllers
import (
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
)
// To be called after pressing up-arrow; checks whether the cursor entered the
@@ -39,7 +38,7 @@ func calculateLinesToScrollUp(viewPortStart int, viewPortHeight int, scrollOffMa
// a very large value to keep the cursor always in the middle of the screen.
// Use +.5 so that if the height is even, the top margin is one line higher
// than the bottom margin.
scrollOffMargin = utils.Min(scrollOffMargin, int((float64(viewPortHeight)+.5)/2))
scrollOffMargin = min(scrollOffMargin, int((float64(viewPortHeight)+.5)/2))
// Scroll only if the "before" position was visible (this could be false if
// the scroll wheel was used to scroll the selected line out of view) ...
@@ -59,7 +58,7 @@ func calculateLinesToScrollDown(viewPortStart int, viewPortHeight int, scrollOff
// a very large value to keep the cursor always in the middle of the screen.
// Use -.5 so that if the height is even, the bottom margin is one line lower
// than the top margin.
scrollOffMargin = utils.Min(scrollOffMargin, int((float64(viewPortHeight)-.5)/2))
scrollOffMargin = min(scrollOffMargin, int((float64(viewPortHeight)-.5)/2))
// Scroll only if the "before" position was visible (this could be false if
// the scroll wheel was used to scroll the selected line out of view) ...

View File

@@ -244,7 +244,7 @@ func (self *StagingController) applySelection(reverse bool) error {
},
)
if err != nil {
return self.c.Error(err)
return err
}
if state.SelectingRange() {
@@ -317,7 +317,7 @@ func (self *StagingController) editHunk() error {
Cached: true,
},
); err != nil {
return self.c.Error(err)
return err
}
return nil

View File

@@ -109,7 +109,7 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
err := self.c.Git().Stash.Apply(stashEntry.Index)
_ = self.postStashRefresh()
if err != nil {
return self.c.Error(err)
return err
}
return nil
}
@@ -133,7 +133,7 @@ func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error
err := self.c.Git().Stash.Pop(stashEntry.Index)
_ = self.postStashRefresh()
if err != nil {
return self.c.Error(err)
return err
}
return nil
}
@@ -160,7 +160,7 @@ func (self *StashController) handleStashDrop(stashEntry *models.StashEntry) erro
err := self.c.Git().Stash.Drop(stashEntry.Index)
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
if err != nil {
return self.c.Error(err)
return err
}
return nil
},

View File

@@ -79,50 +79,19 @@ func (self *StatusController) GetMouseKeybindings(opts types.KeybindingsOpts) []
}
func (self *StatusController) onClickMain(opts gocui.ViewMouseBindingOpts) error {
view := self.c.Views().Main
cx, cy := view.Cursor()
url, err := view.Word(cx, cy)
if err == nil && strings.HasPrefix(url, "https://") {
// Ignore errors (opening the link via the OS can fail if the
// `os.openLink` config key references a command that doesn't exist, or
// that errors when called.)
_ = self.c.OS().OpenLink(url)
}
return nil
return self.c.HandleGenericClick(self.c.Views().Main)
}
func (self *StatusController) GetOnRenderToMain() func() error {
versionStr := "master"
version, err := types.ParseVersionNumber(self.c.GetConfig().GetVersion())
if err == nil {
// Don't just take the version string as is, but format it again. This
// way it will be correct even if a distribution omits the "v", or the
// ".0" at the end.
versionStr = fmt.Sprintf("v%d.%d.%d", version.Major, version.Minor, version.Patch)
}
config := self.c.UserConfig.Gui
return func() error {
dashboardString := strings.Join(
[]string{
lazygitTitle(),
"Copyright 2022 Jesse Duffield",
fmt.Sprintf("Keybindings: %s", style.AttrUnderline.Sprint(fmt.Sprintf(constants.Links.Docs.Keybindings, versionStr))),
fmt.Sprintf("Config Options: %s", style.AttrUnderline.Sprint(fmt.Sprintf(constants.Links.Docs.Config, versionStr))),
fmt.Sprintf("Tutorial: %s", style.AttrUnderline.Sprint(constants.Links.Docs.Tutorial)),
fmt.Sprintf("Raise an Issue: %s", style.AttrUnderline.Sprint(constants.Links.Issues)),
fmt.Sprintf("Release Notes: %s", style.AttrUnderline.Sprint(constants.Links.Releases)),
style.FgMagenta.Sprintf("Become a sponsor: %s", style.AttrUnderline.Sprint(constants.Links.Donate)), // caffeine ain't free
}, "\n\n") + "\n"
return self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: self.c.Tr.StatusTitle,
Task: types.NewRenderStringTask(dashboardString),
},
})
switch config.StatusPanelView {
case "dashboard":
return self.showDashboard
case "allBranchesLog":
return self.showAllBranchLogs
default:
return self.showDashboard
}
}
@@ -147,7 +116,7 @@ func (self *StatusController) onClick() error {
}
cx, _ := self.c.Views().Status.Cursor()
upstreamStatus := presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now())
upstreamStatus := presentation.BranchStatus(currentBranch, types.ItemOperationNone, self.c.Tr, time.Now(), self.c.UserConfig)
repoName := self.c.Git().RepoPaths.RepoName()
workingTreeState := self.c.Git().Status.WorkingTreeState()
switch workingTreeState {
@@ -235,6 +204,37 @@ func (self *StatusController) showAllBranchLogs() error {
})
}
func (self *StatusController) showDashboard() error {
versionStr := "master"
version, err := types.ParseVersionNumber(self.c.GetConfig().GetVersion())
if err == nil {
// Don't just take the version string as is, but format it again. This
// way it will be correct even if a distribution omits the "v", or the
// ".0" at the end.
versionStr = fmt.Sprintf("v%d.%d.%d", version.Major, version.Minor, version.Patch)
}
dashboardString := strings.Join(
[]string{
lazygitTitle(),
fmt.Sprintf("Copyright %d Jesse Duffield", time.Now().Year()),
fmt.Sprintf("Keybindings: %s", style.AttrUnderline.Sprint(fmt.Sprintf(constants.Links.Docs.Keybindings, versionStr))),
fmt.Sprintf("Config Options: %s", style.AttrUnderline.Sprint(fmt.Sprintf(constants.Links.Docs.Config, versionStr))),
fmt.Sprintf("Tutorial: %s", style.AttrUnderline.Sprint(constants.Links.Docs.Tutorial)),
fmt.Sprintf("Raise an Issue: %s", style.AttrUnderline.Sprint(constants.Links.Issues)),
fmt.Sprintf("Release Notes: %s", style.AttrUnderline.Sprint(constants.Links.Releases)),
style.FgMagenta.Sprintf("Become a sponsor: %s", style.AttrUnderline.Sprint(constants.Links.Donate)), // caffeine ain't free
}, "\n\n") + "\n"
return self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: self.c.Tr.StatusTitle,
Task: types.NewRenderStringTask(dashboardString),
},
})
}
func (self *StatusController) handleCheckForUpdate() error {
return self.c.Helpers().Update.CheckForUpdateInForeground()
}

View File

@@ -46,7 +46,7 @@ func (self *SubCommitsController) GetOnRenderToMain() func() error {
if commit == nil {
task = types.NewRenderStringTask("No commits")
} else {
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Sha, self.c.Modes().Filtering.GetPath())
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Hash, self.c.Modes().Filtering.GetPath())
task = types.NewRunPtyTask(cmdObj.GetCmd())
}
@@ -68,10 +68,8 @@ func (self *SubCommitsController) GetOnFocus() func(types.OnFocusOpts) error {
context := self.context()
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
context.SetLimitCommits(false)
self.c.OnWorker(func(_ gocui.Task) {
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUB_COMMITS}}); err != nil {
_ = self.c.Error(err)
}
self.c.OnWorker(func(_ gocui.Task) error {
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUB_COMMITS}})
})
}

View File

@@ -163,7 +163,7 @@ func (self *SubmodulesController) add() error {
self.c.LogAction(self.c.Tr.Actions.AddSubmodule)
err := self.c.Git().Submodule.Add(submoduleName, submodulePath, submoduleUrl)
if err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -185,7 +185,7 @@ func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) err
self.c.LogAction(self.c.Tr.Actions.UpdateSubmoduleUrl)
err := self.c.Git().Submodule.UpdateUrl(submodule, newUrl)
if err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -199,7 +199,7 @@ func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error
self.c.LogAction(self.c.Tr.Actions.InitialiseSubmodule)
err := self.c.Git().Submodule.Init(submodule.Path)
if err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -217,7 +217,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
self.c.LogAction(self.c.Tr.Actions.BulkInitialiseSubmodules)
err := self.c.Git().Submodule.BulkInitCmdObj().Run()
if err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -231,7 +231,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkUpdateSubmodules)
if err := self.c.Git().Submodule.BulkUpdateCmdObj().Run(); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -245,7 +245,7 @@ func (self *SubmodulesController) openBulkActionsMenu() error {
return self.c.WithWaitingStatus(self.c.Tr.RunningCommand, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.BulkDeinitialiseSubmodules)
if err := self.c.Git().Submodule.BulkDeinitCmdObj().Run(); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -262,7 +262,7 @@ func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) erro
self.c.LogAction(self.c.Tr.Actions.UpdateSubmodule)
err := self.c.Git().Submodule.Update(submodule.Path)
if err != nil {
_ = self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}})
@@ -276,7 +276,7 @@ func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) erro
HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.RemoveSubmodule)
if err := self.c.Git().Submodule.Delete(submodule); err != nil {
return self.c.Error(err)
return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES, types.FILES}})

View File

@@ -1,6 +1,7 @@
package controllers
import (
"errors"
"fmt"
"strings"
@@ -101,7 +102,7 @@ func (self *SyncController) push(currentBranch *models.Branch) error {
return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error {
upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream)
if err != nil {
return self.c.Error(err)
return err
}
return self.pushAux(currentBranch, pushOpts{
@@ -121,7 +122,7 @@ func (self *SyncController) pull(currentBranch *models.Branch) error {
if !currentBranch.IsTrackingRemote() {
return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(currentBranch, func(upstream string) error {
if err := self.setCurrentBranchUpstream(upstream); err != nil {
return self.c.Error(err)
return err
}
return self.PullAux(currentBranch, PullFilesOptions{Action: action})
@@ -197,7 +198,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts)
})
if err != nil {
if strings.Contains(err.Error(), "Updates were rejected") {
return self.c.ErrorMsg(self.c.Tr.UpdatesRejected)
return errors.New(self.c.Tr.UpdatesRejected)
}
return err
}
@@ -208,7 +209,7 @@ func (self *SyncController) pushAux(currentBranch *models.Branch, opts pushOpts)
func (self *SyncController) requestToForcePush(currentBranch *models.Branch, opts pushOpts) error {
forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing
if forcePushDisabled {
return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled)
return errors.New(self.c.Tr.ForcePushDisabled)
}
return self.c.Confirm(types.ConfirmOpts{

Some files were not shown because too many files have changed in this diff Show More