Repository: jesseduffield/lazygit (language: go)

Issue:
 Hold down arrow key to switch file,  diff window stop render.
**Describe the bug**
1. Unstaged Changes stop update
2. Exit with error message "cannot kill child process"

**To Reproduce**
1.  Enter Files Window
2.  **Hold Down** the arrow keys (up or down) to switch files, (Single click do not happen)
3.  Un staged changes  or diff window stop update

**Expected behavior**
Un staged Changes windows should to update.

**Screenshots:**
![Snipaste_2021-04-13_00-00-07.png](https://i.loli.net/2021/04/13/xC2Ote1rkplGfWD.png)
![Snipaste_2021-04-13_00-00-30.png](https://i.loli.net/2021/04/13/i9xySEAhpCu8cnU.png)

**Desktop:**
 - OS: Windows
 - Lazy Git Version : v0.27.4

**Additional context**
 I tried it in WSL2 (Ubuntu) and it doesn't have this problem


v0.35 still happen


 Hold down arrow key to switch file,  diff window stop render.
**Describe the bug**
1. Unstaged Changes stop update
2. Exit with error message "cannot kill child process"

**To Reproduce**
1.  Enter Files Window
2.  **Hold Down** the arrow keys (up or down) to switch files, (Single click do not happen)
3.  Un staged changes  or diff window stop update

**Expected behavior**
Un staged Changes windows should to update.

**Screenshots:**
![Snipaste_2021-04-13_00-00-07.png](https://i.loli.net/2021/04/13/xC2Ote1rkplGfWD.png)
![Snipaste_2021-04-13_00-00-30.png](https://i.loli.net/2021/04/13/i9xySEAhpCu8cnU.png)

**Desktop:**
 - OS: Windows
 - Lazy Git Version : v0.27.4

**Additional context**
 I tried it in WSL2 (Ubuntu) and it doesn't have this problem


v0.35 still happen




Discussion / hints:
I tried it in v25 v26 v27 have same problem
I am still having this issue very frequently on v0.31.4
> I am still having this issue very frequently on v0.31.4

![1642348319(1)](https://user-images.githubusercontent.com/22201628/149667274-088e3e7d-2049-43e7-a218-b06b214c5304.jpg)
guy i recommend you use wsl2 (windows subsystem linux).
I can understand suggesting WSL 2 as a work around temporarily, but I don't think it is unreasonable to ask for a fix for this issue. Lazygit claims to support Windows and this bug makes using the tool on Windows irritating.
This is a **major** issue for Windows users, unfortunately. I got to a point where I couldn't use lazygit for more than a few seconds after running it _(unless I wasn't using the file tree, obviously)_. I even stopped using it for the last 2 months.

---

I've done some digging by checking the log tho, here's what I've found:

#### 1. After executing `lazygit` at the source of my repo, the selected file is the **folder** `.tasks`. The `main view` appears and reports `error: Could not access '.tasks/null'`, which is expected.

![lg_launch-folder](https://user-images.githubusercontent.com/36425380/168148766-f1a08672-9d5d-4f7f-b602-b86a70246078.png)

- A first `RunCommand command="git diff --submodule --no-ext-diff --unified=3 --color=always --no-index -- /dev/null .tasks"` is executed, it seems to work without error.
- A second `RunCommand command="git diff [...] .tasks"` is executed, and is followed by the error `error when running cmd task: invalid argument` and then _(I guess)_ the "goroutine" exits itself.

#### 2. I select the next file in the tree, `.tasks/bump.v`. The `main view` appears instantly, it contains the file diff, nothing weird here.

![lg_file](https://user-images.githubusercontent.com/36425380/168152033-27533706-abd7-4e6e-9650-58cb7bbdfbc8.png)

- A first `RunCommand command="git diff --submodule --no-ext-diff --unified=3 --color=always --no-index -- /dev/null .tasks/bump.v"` is executed, followed by the error `error when running cmd task: invalid argument`. It is **not followed**  by `error status 1`.
- A few seconds after the first one, a second `RunCommand command="git diff [...] .tasks/bump.v"` is executed, followed by the error `error when running cmd task: invalid argument`. It is followed by the error `error when running cmd task: TerminateProcess: Access denied`, and then `error status 1`.

#### 3. I hold down <kbd>↓</kbd> _(down arrow key)_ to walk down the file tree. The `main view` freezes.

![lg_walk-file-tree](https://user-images.githubusercontent.com/36425380/168156956-03e357e9-1627-4ab9-a12f-247396105c5c.png)

- Tons of `RunCommand command="git diff [...] {FILE_NAME}"`, but **not a single** `invalid argument`, nor `TerminateProcess: Access denied`, nor `exit status 1`.

#### 4. I exit `lazygit`, and, surprise surprise: `cannot kill child process`.

---

Ok, so now, what happens if I do everything again, but instead of holding down <kbd>↓</kbd>, I press it multiple times ?

#### 1. Executing `lazygit` at the source of my repo.

![lg_launch-folder](https://user-images.githubusercontent.com/36425380/168159213-90af94cd-8291-4e5c-83c5-f09aa6759d75.png)

- **same as before**

#### 2. Pressing <kbd>↓</kbd> multiple times.

![lg_walk-file-tree](https://user-images.githubusercontent.com/36425380/168159890-c854ffcd-bc5c-446d-89dc-365b7be6fc3a.png)
_(I spare you the very-very-very-long screenshot, but the log file is available at the end of my comment)_

- `RunCommand command="git diff [...] {FILE_NAME}"`
- Error `invalid argument`
- Error `TerminateProcess: Access Denied`
- `exit status 1`
- Repeat

The `main view` doesn't freeze, it shows what is expected: **the files diff**.

#### 3. I exit `lazygit`, and, surprise surprise: **no issue**.

[Holding <↓> log file](https://github.com/jesseduffield/lazygit/files/8681847/lazygit_walk_file_tree_error.log)
[Pressing <↓> multiple times log file](https://github.com/jesseduffield/lazygit/files/8682299/lazygit_walk_file_tree.log)

A similar thing is happening for me when I'm using `lazygit` inside toggleterm in neovim.
Terminal - Alacritty
OS - Windows 11

It's working fine when I'm using lazygit directly in Alacritty though. Also, this only happens when I keep the down key pressed and doesn't happen when I keep the up key pressed.
I've done some debugging, but I'm stuck right now.

### What happens when the view freezes

It's a bit difficult to explain because of goroutines, but I'll try my best.

#### 1. NewTask

`gui.newCmdTask()` is called with the command `git diff [...] {FILE_NAME}` to find the diff of the selected file. The `gui.newCmdTask()` function has this line, it's where the beginning of the issue stands:
https://github.com/jesseduffield/lazygit/blob/e68093fe9974296fe5afb22ec8e0adb1eb2f4316/pkg/gui/tasks_adapter.go#L38

`manager.NewTask()` is called, the function starts a goroutine — `NewTask.func1`, and then returns `nil`.

#### 2. NewTask.func1

`NewTask.func1` has a `mutex` that is locked at the start of the function, and is unlocked at the end (with a defer statement):
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L258-L259

After the lock, there are 2 important things, the first one looks like this :
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L265-L278

And the other one is this goroutine (`NewTask.func1.1`):
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L280-L286

`f(stop)` calls `manager.NewCmdTask()`. **When it returns**, the channel `notifyStopped` is closed.

When the bug happens, `self.stopCurrentTask()` is called, so those 2 lines are executed:
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L274-L275

- the channel `stop` is closed
- `NewTask.func1` **waits** for `notifyStopped` to be closed

Something that needs to be noted: `self.waitingMutex` is **NOT UNLOCKED** until `notifyStopped` is closed.

#### 3. NewCmdTask

`NewCmdTask` does many things, so I'm going to make a "summary function":

```go
select {
case <-stop:
    return nil
default:
}

done := make(chan struct{})

scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanLines)

// `NewCmdTask.func1`
go utils.Safe(func() {
outer:
    for {
        // Some lines
        ok := scanner.Scan()
        // Some other lines
        if !ok {
            self.onEndOfInput()
            break outer
        }

    self.refreshView()
    close(done)
}) // End of `NewCmdTask.func1`

<-done
return nil
```

- if `stop` is closed, the function returns instantly
- a channel `done` is created
- a `scanner` is created (it scans stdout of the command `git diff [...] {FILE_NAME}`)
- the function **waits for `done` to be closed before returning**

In parallel (`NewCmdTask.func1`):

- a line is scanned
- if there are no more lines to scan, the for statement breaks out
    - the view is refreshed
    - `done` is closed

And **this is where it all comes together**, when there are no more lines to read:

- the view is refreshed with the content of `git diff [...] {FILE_NAME}`
- `done` is closed
- `NewCmdTask` returns
- `notifyStopped` is closed
- `self.waitingMutex` is unlocked (because `NewTask.func1` returns)

**BUT**, we are talking about a bug, so something messes up at some point, right ?

Well, I don't know why, but it seems like the scanner doesn't scan anymore...

This line hangs (?) indefinitely:
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L172

<details>
<summary>Stack trace of <code>NewCmdTask.func1</code></summary>
<pre>
??? (?:-1)
runtime.systemstack_switch (...\go\src\runtime\asm_amd64.s:436)
runtime.cgocall (...\go\src\runtime\cgocall.go:167)
syscall.SyscallN (...\go\src\runtime\syscall_windows.go:538)
syscall.Syscall6 (.:0)
syscall.ReadFile (...\go\src\syscall\zsyscall_windows.go:1024)
syscall.Read (...\go\src\syscall\syscall_windows.go:380)
internal/poll.(*FD).Read (...\go\src\internal\poll\fd_windows.go:427)
os.(*File).read (...\go\src\os\file_posix.go:31)
os.(*File).Read (...\go\src\os\file.go:119)
bufio.(*Scanner).Scan (...\go\src\bufio\scan.go:215)
github.com/jesseduffield/lazygit/pkg/tasks.(*ViewBufferManager).NewCmdTask.func1.4 (...\lazygit\pkg\tasks\tasks.go:172)
github.com/jesseduffield/lazygit/pkg/utils.Safe.func1 (...\lazygit\pkg\utils\utils.go:104)
github.com/jesseduffield/lazygit/pkg/utils.SafeWithError (...\lazygit\pkg\utils\utils.go:115)
github.com/jesseduffield/lazygit/pkg/utils.Safe (...\lazygit\pkg\utils\utils.go:104)
github.com/jesseduffield/lazygit/pkg/tasks.(*ViewBufferManager).NewCmdTask.func1.7 (...\lazygit\pkg\tasks\tasks.go:158)
runtime.goexit (...\go\src\runtime\asm_amd64.s:1571)
</pre>
</details>

Because of this:

- view is not refreshed
- `done` is not closed
- `NewCmdTask` does not return
- `notifyStopped` is not closed
- `self.waitingMutex` is not unlocked
- ⇒ every time `NewTask` is called, it hangs on `self.waitingMutex.Lock()`
- ⇒ The command `git diff [...] {FILE_NAME}` is never called anymore
- ⇒ The view never refreshes

I don't know what happens with the scanner. I don't understand what happens with the scanner.

Pls help @jesseduffield. I'm going crazy.
great investigation @Aziks0. Some things I've noted while taking a look at the code just now:
1) The start of the process is typically to call gui.newPtyTask, which will itself only call gui.newCmdTask if there's no custom pager being used OR if we're on windows because that gui.newPtyTask function is called is overridden for windows in `pkg/gui/pty_windows.go` (this is because the pty library doesn't yet support windows (see https://github.com/creack/pty/pull/109). I wonder if the problem is that the git command _does_ use a pager (e.g. `less`) and so never returns an EOF to the scanner, meaning we get stuck on `scanner.Scan()`. Scanners block while waiting for new content, but we could swap out the scanner with a plain old reader and would then be able to deal with a lack of new content.

2) The in-built process killing method doesn't handle child processes of a windows process. I've got a PR to handle this, adapted from the approach we take in lazydocker. @Aziks0 would you be able to see if the issue persists on this PR? https://github.com/jesseduffield/lazygit/pull/2006
@jesseduffield 

1. I've tried with and without a pager a few months ago, it didn't change anything to not have one. I've retried today, no difference.
2. The issue persist, unfortunately :(. It is not better or worst, just the same as before.
Btw, if I hold down <kbd>↓</kbd> instantly after executing lazygit, the issue appears instantly. If I wait a few seconds before holding down <kbd>↓</kbd>/<kbd>↑</kbd>, the issue appears more randomly.

https://user-images.githubusercontent.com/36425380/174432026-88c1d836-33be-42fe-978c-782f2ea7af49.mp4
I am also experiencing this annoying issue. Really liked using lazygit, but no I'm back to using the command line git tools, as it is better than pulling my hair out every time the diff view freezes. Any updates on this? Can I do something to help? 
Could you maybe try the latest `master`? There were a few updates regarding `gocui`
After upgrading to the latest lazygit, the problem never occurred again
may be we can make a release soon then? it's a pretty major thing to push out IMO!
Last release was a month ago, does it still happen with `v0.37.0`?
Yes, still happening on v0.37.0
![2023-03-07_19-43-42](https://user-images.githubusercontent.com/658865/223344643-a246cb33-22ba-4d2d-b40b-024186287b1b.png)

Unstaged changes stop updating too.
@AndrewSav and just to confirm, you don't have any issues on latest master as well?
@mark2185 I can try latest master if there is a release that is built from the latest master.
> @mark2185 I can try latest master if there is a release that is built from the latest master.

There isn't, I meant could you try building the latest `master` and see if it happens there as well?
@mark2185 done. results below. os: windows 10

![lazygit](https://user-images.githubusercontent.com/32834752/223686694-0628bd9f-1e8c-4a1b-b399-446913c3ae47.gif)

hello, just wanted to follow up to see if anyone is still looking at this?
Hey, just wanted to share my experience. I did a few things which did not completely eliminate the occurrence of the issue, but brought down the frequency with which it's occurring. I think this may be a combination of factors:

- It happen less with (new) Windows Terminal. If using alacrity or conemu I can reproduce it much faster
- It happens less if git is NOT installed from scoop, scoop adds a shim which adds friction, again when git is installed from scoop I can reproduce it faster
- When `lazygit` gets to a bugged state there are one or more suspended `git` processes sitting in the task manager. I believe this explains scanner not scanning - the pipe is there but the process is suspended. If I run `Get-Process git | Stop-Process` the panels start refreshing again. I do not offer this as a work around, since it's much simpler just to quit `lazygit` and re-run it, just as an additional data point.

Replacing scanner with a reader as suggested above might help, and also if someone smart enough can figure out why we get these suspended git processes, we might finally resolve this issue.

**Update**

Git for Windows _also_ has a shim: `C:\Program Files\Git\cmd` has a shim and `C:\Program Files\Git\mingw64\bin` has the actual binary. Once I put the latter at the top of the path like this:

![2023-07-14_12-59-42](https://github.com/jesseduffield/lazygit/assets/658865/92007282-e633-4527-89c2-764d68ff5a31)

I can no longer reproduce the issue. (Make sure that your lazygit process has the environment block that reflects this change, rebooting will take care of this, but there are easier but less reliable ways)


I tried it in v25 v26 v27 have same problem
I am still having this issue very frequently on v0.31.4
> I am still having this issue very frequently on v0.31.4

![1642348319(1)](https://user-images.githubusercontent.com/22201628/149667274-088e3e7d-2049-43e7-a218-b06b214c5304.jpg)
guy i recommend you use wsl2 (windows subsystem linux).
I can understand suggesting WSL 2 as a work around temporarily, but I don't think it is unreasonable to ask for a fix for this issue. Lazygit claims to support Windows and this bug makes using the tool on Windows irritating.
This is a **major** issue for Windows users, unfortunately. I got to a point where I couldn't use lazygit for more than a few seconds after running it _(unless I wasn't using the file tree, obviously)_. I even stopped using it for the last 2 months.

---

I've done some digging by checking the log tho, here's what I've found:

#### 1. After executing `lazygit` at the source of my repo, the selected file is the **folder** `.tasks`. The `main view` appears and reports `error: Could not access '.tasks/null'`, which is expected.

![lg_launch-folder](https://user-images.githubusercontent.com/36425380/168148766-f1a08672-9d5d-4f7f-b602-b86a70246078.png)

- A first `RunCommand command="git diff --submodule --no-ext-diff --unified=3 --color=always --no-index -- /dev/null .tasks"` is executed, it seems to work without error.
- A second `RunCommand command="git diff [...] .tasks"` is executed, and is followed by the error `error when running cmd task: invalid argument` and then _(I guess)_ the "goroutine" exits itself.

#### 2. I select the next file in the tree, `.tasks/bump.v`. The `main view` appears instantly, it contains the file diff, nothing weird here.

![lg_file](https://user-images.githubusercontent.com/36425380/168152033-27533706-abd7-4e6e-9650-58cb7bbdfbc8.png)

- A first `RunCommand command="git diff --submodule --no-ext-diff --unified=3 --color=always --no-index -- /dev/null .tasks/bump.v"` is executed, followed by the error `error when running cmd task: invalid argument`. It is **not followed**  by `error status 1`.
- A few seconds after the first one, a second `RunCommand command="git diff [...] .tasks/bump.v"` is executed, followed by the error `error when running cmd task: invalid argument`. It is followed by the error `error when running cmd task: TerminateProcess: Access denied`, and then `error status 1`.

#### 3. I hold down <kbd>↓</kbd> _(down arrow key)_ to walk down the file tree. The `main view` freezes.

![lg_walk-file-tree](https://user-images.githubusercontent.com/36425380/168156956-03e357e9-1627-4ab9-a12f-247396105c5c.png)

- Tons of `RunCommand command="git diff [...] {FILE_NAME}"`, but **not a single** `invalid argument`, nor `TerminateProcess: Access denied`, nor `exit status 1`.

#### 4. I exit `lazygit`, and, surprise surprise: `cannot kill child process`.

---

Ok, so now, what happens if I do everything again, but instead of holding down <kbd>↓</kbd>, I press it multiple times ?

#### 1. Executing `lazygit` at the source of my repo.

![lg_launch-folder](https://user-images.githubusercontent.com/36425380/168159213-90af94cd-8291-4e5c-83c5-f09aa6759d75.png)

- **same as before**

#### 2. Pressing <kbd>↓</kbd> multiple times.

![lg_walk-file-tree](https://user-images.githubusercontent.com/36425380/168159890-c854ffcd-bc5c-446d-89dc-365b7be6fc3a.png)
_(I spare you the very-very-very-long screenshot, but the log file is available at the end of my comment)_

- `RunCommand command="git diff [...] {FILE_NAME}"`
- Error `invalid argument`
- Error `TerminateProcess: Access Denied`
- `exit status 1`
- Repeat

The `main view` doesn't freeze, it shows what is expected: **the files diff**.

#### 3. I exit `lazygit`, and, surprise surprise: **no issue**.

[Holding <↓> log file](https://github.com/jesseduffield/lazygit/files/8681847/lazygit_walk_file_tree_error.log)
[Pressing <↓> multiple times log file](https://github.com/jesseduffield/lazygit/files/8682299/lazygit_walk_file_tree.log)

A similar thing is happening for me when I'm using `lazygit` inside toggleterm in neovim.
Terminal - Alacritty
OS - Windows 11

It's working fine when I'm using lazygit directly in Alacritty though. Also, this only happens when I keep the down key pressed and doesn't happen when I keep the up key pressed.
I've done some debugging, but I'm stuck right now.

### What happens when the view freezes

It's a bit difficult to explain because of goroutines, but I'll try my best.

#### 1. NewTask

`gui.newCmdTask()` is called with the command `git diff [...] {FILE_NAME}` to find the diff of the selected file. The `gui.newCmdTask()` function has this line, it's where the beginning of the issue stands:
https://github.com/jesseduffield/lazygit/blob/e68093fe9974296fe5afb22ec8e0adb1eb2f4316/pkg/gui/tasks_adapter.go#L38

`manager.NewTask()` is called, the function starts a goroutine — `NewTask.func1`, and then returns `nil`.

#### 2. NewTask.func1

`NewTask.func1` has a `mutex` that is locked at the start of the function, and is unlocked at the end (with a defer statement):
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L258-L259

After the lock, there are 2 important things, the first one looks like this :
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L265-L278

And the other one is this goroutine (`NewTask.func1.1`):
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L280-L286

`f(stop)` calls `manager.NewCmdTask()`. **When it returns**, the channel `notifyStopped` is closed.

When the bug happens, `self.stopCurrentTask()` is called, so those 2 lines are executed:
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L274-L275

- the channel `stop` is closed
- `NewTask.func1` **waits** for `notifyStopped` to be closed

Something that needs to be noted: `self.waitingMutex` is **NOT UNLOCKED** until `notifyStopped` is closed.

#### 3. NewCmdTask

`NewCmdTask` does many things, so I'm going to make a "summary function":

```go
select {
case <-stop:
    return nil
default:
}

done := make(chan struct{})

scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanLines)

// `NewCmdTask.func1`
go utils.Safe(func() {
outer:
    for {
        // Some lines
        ok := scanner.Scan()
        // Some other lines
        if !ok {
            self.onEndOfInput()
            break outer
        }

    self.refreshView()
    close(done)
}) // End of `NewCmdTask.func1`

<-done
return nil
```

- if `stop` is closed, the function returns instantly
- a channel `done` is created
- a `scanner` is created (it scans stdout of the command `git diff [...] {FILE_NAME}`)
- the function **waits for `done` to be closed before returning**

In parallel (`NewCmdTask.func1`):

- a line is scanned
- if there are no more lines to scan, the for statement breaks out
    - the view is refreshed
    - `done` is closed

And **this is where it all comes together**, when there are no more lines to read:

- the view is refreshed with the content of `git diff [...] {FILE_NAME}`
- `done` is closed
- `NewCmdTask` returns
- `notifyStopped` is closed
- `self.waitingMutex` is unlocked (because `NewTask.func1` returns)

**BUT**, we are talking about a bug, so something messes up at some point, right ?

Well, I don't know why, but it seems like the scanner doesn't scan anymore...

This line hangs (?) indefinitely:
https://github.com/jesseduffield/lazygit/blob/3bf0c9ef441f9343172ed71b5e5947c69e66ac9a/pkg/tasks/tasks.go#L172

<details>
<summary>Stack trace of <code>NewCmdTask.func1</code></summary>
<pre>
??? (?:-1)
runtime.systemstack_switch (...\go\src\runtime\asm_amd64.s:436)
runtime.cgocall (...\go\src\runtime\cgocall.go:167)
syscall.SyscallN (...\go\src\runtime\syscall_windows.go:538)
syscall.Syscall6 (.:0)
syscall.ReadFile (...\go\src\syscall\zsyscall_windows.go:1024)
syscall.Read (...\go\src\syscall\syscall_windows.go:380)
internal/poll.(*FD).Read (...\go\src\internal\poll\fd_windows.go:427)
os.(*File).read (...\go\src\os\file_posix.go:31)
os.(*File).Read (...\go\src\os\file.go:119)
bufio.(*Scanner).Scan (...\go\src\bufio\scan.go:215)
github.com/jesseduffield/lazygit/pkg/tasks.(*ViewBufferManager).NewCmdTask.func1.4 (...\lazygit\pkg\tasks\tasks.go:172)
github.com/jesseduffield/lazygit/pkg/utils.Safe.func1 (...\lazygit\pkg\utils\utils.go:104)
github.com/jesseduffield/lazygit/pkg/utils.SafeWithError (...\lazygit\pkg\utils\utils.go:115)
github.com/jesseduffield/lazygit/pkg/utils.Safe (...\lazygit\pkg\utils\utils.go:104)
github.com/jesseduffield/lazygit/pkg/tasks.(*ViewBufferManager).NewCmdTask.func1.7 (...\lazygit\pkg\tasks\tasks.go:158)
runtime.goexit (...\go\src\runtime\asm_amd64.s:1571)
</pre>
</details>

Because of this:

- view is not refreshed
- `done` is not closed
- `NewCmdTask` does not return
- `notifyStopped` is not closed
- `self.waitingMutex` is not unlocked
- ⇒ every time `NewTask` is called, it hangs on `self.waitingMutex.Lock()`
- ⇒ The command `git diff [...] {FILE_NAME}` is never called anymore
- ⇒ The view never refreshes

I don't know what happens with the scanner. I don't understand what happens with the scanner.

Pls help @jesseduffield. I'm going crazy.
great investigation @Aziks0. Some things I've noted while taking a look at the code just now:
1) The start of the process is typically to call gui.newPtyTask, which will itself only call gui.newCmdTask if there's no custom pager being used OR if we're on windows because that gui.newPtyTask function is called is overridden for windows in `pkg/gui/pty_windows.go` (this is because the pty library doesn't yet support windows (see https://github.com/creack/pty/pull/109). I wonder if the problem is that the git command _does_ use a pager (e.g. `less`) and so never returns an EOF to the scanner, meaning we get stuck on `scanner.Scan()`. Scanners block while waiting for new content, but we could swap out the scanner with a plain old reader and would then be able to deal with a lack of new content.

2) The in-built process killing method doesn't handle child processes of a windows process. I've got a PR to handle this, adapted from the approach we take in lazydocker. @Aziks0 would you be able to see if the issue persists on this PR? https://github.com/jesseduffield/lazygit/pull/2006
@jesseduffield 

1. I've tried with and without a pager a few months ago, it didn't change anything to not have one. I've retried today, no difference.
2. The issue persist, unfortunately :(. It is not better or worst, just the same as before.
Btw, if I hold down <kbd>↓</kbd> instantly after executing lazygit, the issue appears instantly. If I wait a few seconds before holding down <kbd>↓</kbd>/<kbd>↑</kbd>, the issue appears more randomly.

https://user-images.githubusercontent.com/36425380/174432026-88c1d836-33be-42fe-978c-782f2ea7af49.mp4
I am also experiencing this annoying issue. Really liked using lazygit, but no I'm back to using the command line git tools, as it is better than pulling my hair out every time the diff view freezes. Any updates on this? Can I do something to help? 
Could you maybe try the latest `master`? There were a few updates regarding `gocui`
After upgrading to the latest lazygit, the problem never occurred again
may be we can make a release soon then? it's a pretty major thing to push out IMO!
Last release was a month ago, does it still happen with `v0.37.0`?
Yes, still happening on v0.37.0
![2023-03-07_19-43-42](https://user-images.githubusercontent.com/658865/223344643-a246cb33-22ba-4d2d-b40b-024186287b1b.png)

Unstaged changes stop updating too.
@AndrewSav and just to confirm, you don't have any issues on latest master as well?
@mark2185 I can try latest master if there is a release that is built from the latest master.
> @mark2185 I can try latest master if there is a release that is built from the latest master.

There isn't, I meant could you try building the latest `master` and see if it happens there as well?
@mark2185 done. results below. os: windows 10

![lazygit](https://user-images.githubusercontent.com/32834752/223686694-0628bd9f-1e8c-4a1b-b399-446913c3ae47.gif)

hello, just wanted to follow up to see if anyone is still looking at this?
Hey, just wanted to share my experience. I did a few things which did not completely eliminate the occurrence of the issue, but brought down the frequency with which it's occurring. I think this may be a combination of factors:

- It happen less with (new) Windows Terminal. If using alacrity or conemu I can reproduce it much faster
- It happens less if git is NOT installed from scoop, scoop adds a shim which adds friction, again when git is installed from scoop I can reproduce it faster
- When `lazygit` gets to a bugged state there are one or more suspended `git` processes sitting in the task manager. I believe this explains scanner not scanning - the pipe is there but the process is suspended. If I run `Get-Process git | Stop-Process` the panels start refreshing again. I do not offer this as a work around, since it's much simpler just to quit `lazygit` and re-run it, just as an additional data point.

Replacing scanner with a reader as suggested above might help, and also if someone smart enough can figure out why we get these suspended git processes, we might finally resolve this issue.

**Update**

Git for Windows _also_ has a shim: `C:\Program Files\Git\cmd` has a shim and `C:\Program Files\Git\mingw64\bin` has the actual binary. Once I put the latter at the top of the path like this:

![2023-07-14_12-59-42](https://github.com/jesseduffield/lazygit/assets/658865/92007282-e633-4527-89c2-764d68ff5a31)

I can no longer reproduce the issue. (Make sure that your lazygit process has the environment block that reflects this change, rebooting will take care of this, but there are easier but less reliable ways)



Fix patch:
diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go
index ad227fc65d2..9aa03061eed 100644
--- a/pkg/tasks/tasks.go
+++ b/pkg/tasks/tasks.go
@@ -147,6 +147,20 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
 		scanner := bufio.NewScanner(r)
 		scanner.Split(bufio.ScanLines)
 
+		data := make(chan []byte)
+
+		// We're reading from the scanner in a separate goroutine because on windows
+		// if running git through a shim, we sometimes kill the parent process without
+		// killing its children, meaning the scanner blocks forever. This solution
+		// leaves us with a dead goroutine, but it's better than blocking all
+		// rendering to main views.
+		go utils.Safe(func() {
+			for scanner.Scan() {
+				data <- scanner.Bytes()
+			}
+			close(data)
+		})
+
 		loaded := false
 
 		go utils.Safe(func() {
@@ -186,13 +200,15 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
 					break outer
 				case linesToRead := <-self.readLines:
 					for i := 0; i < linesToRead.Total; i++ {
+						var ok bool
+						var line []byte
 						select {
 						case <-stop:
 							break outer
-						default:
+						case line, ok = <-data:
+							break
 						}
 
-						ok := scanner.Scan()
 						loadingMutex.Lock()
 						if !loaded {
 							self.beforeStart()
@@ -209,7 +225,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
 							self.onEndOfInput()
 							break outer
 						}
-						writeToView(append(scanner.Bytes(), '\n'))
+						writeToView(append(line, '\n'))
 
 						if i+1 == linesToRead.InitialRefreshAfter {
 							// We have read enough lines to fill the view, so do a first refresh


Test patch: