mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-29 18:46:55 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc4b50f817 | ||
|
|
0a73123a66 | ||
|
|
2961c991a4 | ||
|
|
a6001dc76e | ||
|
|
9f23b89e90 | ||
|
|
a6096f4702 | ||
|
|
08ad8a0b2d | ||
|
|
3ea4cf0b63 | ||
|
|
9290c074f7 | ||
|
|
ca06ce6100 | ||
|
|
bc0cddf03d | ||
|
|
4b33efffbe | ||
|
|
80a614d330 | ||
|
|
61ff8a4da8 | ||
|
|
039831a27a | ||
|
|
ce9fbe58b2 | ||
|
|
ef1a141347 | ||
|
|
42bbe965fa | ||
|
|
a8e98593ea | ||
|
|
6b1cab7011 | ||
|
|
dc795b5db7 | ||
|
|
0fc107c8c1 | ||
|
|
09a4e0b209 | ||
|
|
6479c52fb2 | ||
|
|
3f3e942f60 | ||
|
|
e7cb469fd0 | ||
|
|
9511ed9d2c | ||
|
|
2a7ce19b73 | ||
|
|
908975c758 | ||
|
|
a83fc5e343 | ||
|
|
2c206c374d | ||
|
|
50785a2217 | ||
|
|
91d8c25183 | ||
|
|
3df894ec92 | ||
|
|
c440a208a6 | ||
|
|
32bd9e6029 | ||
|
|
823aa640b9 | ||
|
|
00d043d743 | ||
|
|
eebc39d3e9 | ||
|
|
92c9eb614f | ||
|
|
ef16867ff1 | ||
|
|
edcfce22f0 | ||
|
|
c87661dbee | ||
|
|
d82852a909 | ||
|
|
2b1f150129 | ||
|
|
5be97c6145 | ||
|
|
80e20417a8 | ||
|
|
ee62878e6b | ||
|
|
2a5970265d | ||
|
|
d60a843c23 | ||
|
|
36388e58b9 | ||
|
|
ca05a2ccea | ||
|
|
7aa426fa71 | ||
|
|
0471dbaa84 | ||
|
|
1e92d8b7f3 | ||
|
|
d9e299c1df | ||
|
|
9b54dc0b28 | ||
|
|
c4de94cff0 | ||
|
|
92093ce56a | ||
|
|
c7d0aaa786 | ||
|
|
4604227238 | ||
|
|
b7aecf5f17 | ||
|
|
8c574f888c | ||
|
|
7ebf5fff0f | ||
|
|
4439531906 | ||
|
|
e5b09f34e0 | ||
|
|
b12b1040c3 | ||
|
|
718cbdb48c | ||
|
|
03abdfcfe2 | ||
|
|
f95ac6780f | ||
|
|
61815c10e7 | ||
|
|
7a8937279a | ||
|
|
f07c08a071 | ||
|
|
75ee875194 | ||
|
|
9e05e4d810 | ||
|
|
ef6f96bda3 | ||
|
|
b5c2524d75 | ||
|
|
80887f5791 | ||
|
|
b5c284db39 | ||
|
|
159efdef9f | ||
|
|
206283d1f7 | ||
|
|
ec0f4d242e | ||
|
|
fd270768e8 | ||
|
|
5ee5d42511 | ||
|
|
4c92ffda60 | ||
|
|
80bbdf41fb | ||
|
|
fb2c5ea8b6 | ||
|
|
265557afa2 | ||
|
|
aa23a6e2b5 | ||
|
|
708b30ab8a |
@@ -169,9 +169,9 @@ jobs:
|
||||
with:
|
||||
go-version: 1.24.x
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@v6.5.0
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
version: v1.64.6
|
||||
version: v2.2.1
|
||||
- name: errors
|
||||
run: golangci-lint run
|
||||
if: ${{ failure() }}
|
||||
|
||||
+108
-34
@@ -1,36 +1,110 @@
|
||||
linters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- thelper
|
||||
- goimports
|
||||
- tparallel
|
||||
- wastedassign
|
||||
- unparam
|
||||
- prealloc
|
||||
- unconvert
|
||||
- exhaustive
|
||||
- makezero
|
||||
- nakedret
|
||||
- copyloopvar
|
||||
fast: false
|
||||
|
||||
linters-settings:
|
||||
copyloopvar:
|
||||
# Check all assigning the loop variable to another variable.
|
||||
# Default: false
|
||||
# If true, an assignment like `a := x` will be detected as an error.
|
||||
check-alias: true
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
staticcheck:
|
||||
# SA1019 is for checking that we're not using fields marked as deprecated
|
||||
# in a comment. It decides this in a loose way so I'm silencing it. Also because
|
||||
# it's tripping on our own structs.
|
||||
checks: ["all", "-SA1019"]
|
||||
nakedret:
|
||||
# the gods will judge me but I just don't like naked returns at all
|
||||
max-func-lines: 0
|
||||
|
||||
version: "2"
|
||||
run:
|
||||
go: "1.24"
|
||||
timeout: 10m
|
||||
linters:
|
||||
enable:
|
||||
- copyloopvar
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- intrange
|
||||
- makezero
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- revive
|
||||
- thelper
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- wastedassign
|
||||
settings:
|
||||
copyloopvar:
|
||||
check-alias: true
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
nakedret:
|
||||
# the gods will judge me but I just don't like naked returns at all
|
||||
max-func-lines: 0
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
|
||||
# SA1019 is for checking that we're not using fields marked as
|
||||
# deprecated in a comment. It decides this in a loose way so I'm
|
||||
# silencing it. Also because it's tripping on our own structs.
|
||||
- -SA1019
|
||||
|
||||
# ST1003 complains about names like remoteUrl or itemId (should be
|
||||
# remoteURL and itemID). While I like these suggestions, it also
|
||||
# complains about enum constants that are all caps, and we use these and
|
||||
# I like them, and also about camelCase identifiers that contain an
|
||||
# underscore, which we also use in a few places. Since it can't be
|
||||
# configured to ignore specific cases, and I don't want to use nolint
|
||||
# comments in the code, we have to disable it altogether.
|
||||
- -ST1003 # Poorly chosen identifier
|
||||
|
||||
# Probably a good idea, but we first have to review our error reporting
|
||||
# strategy to be able to use it everywhere.
|
||||
- -ST1005 # Error strings should not be capitalized
|
||||
|
||||
# Many of our classes use self as a receiver name, and we think that's fine.
|
||||
- -ST1006 # Use of self or this as receiver name
|
||||
|
||||
# De Morgan's law suggests to replace `!(a && b)` with `!a || !b`; but
|
||||
# sometimes I find one more readable than the other, so I want to decide
|
||||
# that myself.
|
||||
- -QF1001 # De Morgan's law
|
||||
|
||||
# QF1003 is about using a tagged switch instead of an if-else chain. In
|
||||
# many cases this is a useful suggestion; however, sometimes the change
|
||||
# is only possible by adding a default case to the switch (when there
|
||||
# was no `else` block in the original code), in which case I don't find
|
||||
# it to be an improvement.
|
||||
- -QF1003 # Could replace with tagged switch
|
||||
|
||||
# We need to review our use of embedded fields. I suspect that in some
|
||||
# cases the fix is not to remove the selector for the embedded field,
|
||||
# but to turn the embedded field into a named field.
|
||||
- -QF1008 # Could remove embedded field from selector
|
||||
|
||||
# The following checks are all disabled by default in golangci-lint, but
|
||||
# we disable them again explicitly here to make it easier to keep this
|
||||
# list in sync with the gopls config in .vscode/settings.json.
|
||||
- -ST1000, # At least one file in a package should have a package comment
|
||||
- -ST1020, # The documentation of an exported function should start with the function's name
|
||||
- -ST1021, # The documentation of an exported type should start with type's name
|
||||
- -ST1022, # The documentation of an exported variable or constant should start with variable's name
|
||||
|
||||
dot-import-whitelist:
|
||||
- github.com/jesseduffield/lazygit/pkg/integration/components
|
||||
revive:
|
||||
severity: warning
|
||||
rules:
|
||||
- name: atomic
|
||||
- name: context-as-argument
|
||||
- name: context-keys-type
|
||||
- name: error-naming
|
||||
- name: var-declaration
|
||||
- name: package-comments
|
||||
- name: range
|
||||
- name: time-naming
|
||||
- name: indent-error-flow
|
||||
- name: errorf
|
||||
- name: superfluous-else
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- vendor/
|
||||
formatters:
|
||||
enable:
|
||||
- gofumpt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- vendor/
|
||||
|
||||
Vendored
+24
@@ -1,5 +1,29 @@
|
||||
{
|
||||
"gopls": {
|
||||
"formatting.gofumpt": true,
|
||||
"ui.diagnostic.staticcheck": true,
|
||||
"ui.diagnostic.analyses": {
|
||||
// This list must match the one in .golangci.yml
|
||||
"SA1019": false,
|
||||
"ST1003": false,
|
||||
"ST1005": false,
|
||||
"ST1006": false,
|
||||
"QF1001": false,
|
||||
"QF1003": false,
|
||||
"QF1008": false,
|
||||
"ST1000": false,
|
||||
"ST1020": false,
|
||||
"ST1021": false,
|
||||
"ST1022": false,
|
||||
// Dot imports; this warning is enabled in .golangci.yml, but with an
|
||||
// extra dot-import-whitelist config. Because I couldn't figure out how to
|
||||
// specify that extra config for gopls, I'm disabling the check altogether
|
||||
// here.
|
||||
"ST1001": false,
|
||||
},
|
||||
},
|
||||
"go.alternateTools": {
|
||||
"golangci-lint-v2": "${workspaceFolder}/.bin/golangci-lint",
|
||||
},
|
||||
"go.lintTool": "golangci-lint-v2",
|
||||
}
|
||||
|
||||
Vendored
+6
-3
@@ -24,22 +24,24 @@
|
||||
{
|
||||
"label": "Run current file integration test",
|
||||
"type": "shell",
|
||||
"command": "go generate pkg/integration/tests/tests.go && go run cmd/integration_test/main.go cli ${relativeFile}",
|
||||
"command": "go run cmd/integration_test/main.go cli ${relativeFile}",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"clear": true,
|
||||
"focus": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Run current file integration test (slow)",
|
||||
"type": "shell",
|
||||
"command": "go generate pkg/integration/tests/tests.go && go run cmd/integration_test/main.go cli --slow ${relativeFile}",
|
||||
"command": "go run cmd/integration_test/main.go cli --slow ${relativeFile}",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"clear": true,
|
||||
"kind": "test",
|
||||
},
|
||||
"presentation": {
|
||||
@@ -49,12 +51,13 @@
|
||||
{
|
||||
"label": "Run current file integration test (sandbox)",
|
||||
"type": "shell",
|
||||
"command": "go generate pkg/integration/tests/tests.go && go run cmd/integration_test/main.go cli --sandbox ${relativeFile}",
|
||||
"command": "go run cmd/integration_test/main.go cli --sandbox ${relativeFile}",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "test",
|
||||
},
|
||||
"presentation": {
|
||||
"clear": true,
|
||||
"focus": true
|
||||
}
|
||||
},
|
||||
|
||||
@@ -40,7 +40,7 @@ format:
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
golangci-lint run
|
||||
./scripts/lint.sh
|
||||
|
||||
# For more details about integration test, see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md.
|
||||
.PHONY: integration-test-tui
|
||||
|
||||
@@ -194,7 +194,7 @@ Say you're on a feature branch that was itself branched off of the develop branc
|
||||
|
||||
### Undo
|
||||
|
||||
You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions.
|
||||
You can undo the last action by pressing `z` and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions.
|
||||
Undo uses the reflog which is specific to commits and branches so we can't undo changes to the working tree or stash.
|
||||
|
||||
[More info](/docs/Undoing.md)
|
||||
|
||||
+7
-1
@@ -72,6 +72,9 @@ gui:
|
||||
# When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
|
||||
mouseEvents: true
|
||||
|
||||
# If true, do not show a warning when amending a commit.
|
||||
skipAmendWarning: false
|
||||
|
||||
# If true, do not show a warning when discarding changes in the staging view.
|
||||
skipDiscardChangeWarning: false
|
||||
|
||||
@@ -113,6 +116,9 @@ gui:
|
||||
# paragraphs of markdown text.
|
||||
wrapLinesInStagingView: true
|
||||
|
||||
# If true, hunk selection mode will be enabled by default when entering the staging view.
|
||||
useHunkModeInStagingView: false
|
||||
|
||||
# One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
|
||||
language: auto
|
||||
|
||||
@@ -245,7 +251,7 @@ gui:
|
||||
screenMode: normal
|
||||
|
||||
# Window border style.
|
||||
# One of 'rounded' (default) | 'single' | 'double' | 'hidden'
|
||||
# One of 'rounded' (default) | 'single' | 'double' | 'hidden' | 'bold'
|
||||
border: rounded
|
||||
|
||||
# If true, show a seriously epic explosion animation when nuking the working tree.
|
||||
|
||||
+309
-294
@@ -1,346 +1,314 @@
|
||||
_This file is auto-generated. To update, make the changes in the pkg/i18n directory and then run `go generate ./...` from the project root._
|
||||
|
||||
# Lazygit キーバインド
|
||||
# Lazygit キーバインディング
|
||||
|
||||
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
_凡例:`<c-b>` はctrl+b、`<a-b>` はalt+b、`B` はshift+bを意味します_
|
||||
|
||||
## グローバルキーバインド
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-r> `` | 最近使用したリポジトリに切り替え | |
|
||||
| `` <pgup> (fn+up/shift+k) `` | メインパネルを上にスクロール | |
|
||||
| `` <pgdown> (fn+down/shift+j) `` | メインパネルを下にスクロール | |
|
||||
| `` @ `` | コマンドログメニューを開く | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||
| `` P `` | Push | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` p `` | Pull | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` } `` | Increase diff context size | Increase the amount of the context shown around changes in the diff view. |
|
||||
| `` { `` | Decrease diff context size | Decrease the amount of the context shown around changes in the diff view. |
|
||||
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||
| `` <c-p> `` | View custom patch options | |
|
||||
| `` m `` | View merge/rebase options | View options to abort/continue/skip the current merge/rebase. |
|
||||
| `` R `` | リフレッシュ | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||
| `` + `` | 次のスクリーンモード (normal/half/fullscreen) | |
|
||||
| `` _ `` | 前のスクリーンモード | |
|
||||
| `` ? `` | メニューを開く | |
|
||||
| `` <c-s> `` | View filter options | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||
| `` W `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||
| `` <c-e> `` | 差分メニューを開く | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||
| `` <c-r> `` | 最近のリポジトリをチェックアウト | |
|
||||
| `` <pgup> (fn+up/shift+k) `` | メインウィンドウを上にスクロール | |
|
||||
| `` <pgdown> (fn+down/shift+j) `` | メインウィンドウを下にスクロール | |
|
||||
| `` @ `` | コマンドログオプションを表示 | コマンドログのオプションを表示します(例:コマンドログの表示/非表示、コマンドログへのフォーカスなど)。 |
|
||||
| `` P `` | プッシュ | 現在のブランチを対応するアップストリームブランチにプッシュします。アップストリームが設定されていない場合、アップストリームブランチの設定を求められます。 |
|
||||
| `` p `` | プル | 現在のブランチのリモートから変更をプルします。アップストリームが設定されていない場合、アップストリームブランチの設定を求められます。 |
|
||||
| `` ) `` | リネーム検出の類似度しきい値を上げる | ファイルの削除と追加をリネーム(ファイル名変更)と判断するための類似度しきい値を上げます。値を上げると、より似ているファイルのみがリネームと認識されます。 |
|
||||
| `` ( `` | リネーム検出の類似度しきい値を下げる | ファイルの削除と追加をリネーム(ファイル名変更)と判断するための類似度しきい値を下げます。値を下げると、より多くのファイルペアがリネームと認識されます。 |
|
||||
| `` } `` | 差分コンテキストサイズを増やす | 差分ビューで変更の周りに表示されるコンテキストの量を増やします。 |
|
||||
| `` { `` | 差分コンテキストサイズを減らす | 差分ビューで変更の周りに表示されるコンテキストの量を減らします。 |
|
||||
| `` : `` | シェルコマンドを実行 | 実行するシェルコマンドを入力するプロンプトを表示します。 |
|
||||
| `` <c-p> `` | カスタムパッチオプションを表示 | |
|
||||
| `` m `` | マージ/リベースオプションを表示 | 現在のマージ/リベースを中止/継続/スキップするオプションを表示します。 |
|
||||
| `` R `` | 更新 | Gitの状態を更新します(`git status`、`git branch`などをバックグラウンドで実行してパネルの内容を更新します)。これは`git fetch`を実行しません。 |
|
||||
| `` + `` | 次の画面モード(通常/半分/全画面) | |
|
||||
| `` _ `` | 前の画面モード | |
|
||||
| `` ? `` | キーバインディングメニューを開く | |
|
||||
| `` <c-s> `` | フィルターオプションを表示 | コミットログのフィルタリングオプションを表示し、フィルタに一致するコミットのみを表示します。 |
|
||||
| `` W `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 |
|
||||
| `` <c-e> `` | 差分オプションを表示 | 2つのrefの差分に関連するオプションを表示します(例:選択したrefとの差分表示、差分を取るrefの入力、差分方向の反転など)。 |
|
||||
| `` q `` | 終了 | |
|
||||
| `` <esc> `` | キャンセル | |
|
||||
| `` <c-w> `` | 空白文字の差分の表示有無を切り替え | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||
| `` z `` | アンドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||
| `` <c-z> `` | リドゥ (via reflog) (experimental) | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||
| `` <c-w> `` | 空白表示の切り替え | 差分ビューで空白の変更を表示するかどうかを切り替えます。 |
|
||||
| `` z `` | 元に戻す | 最後のgitコマンドを元に戻すために実行するgitコマンドを決定するためにreflogが使用されます。これにはワーキングツリーへの変更は含まれません。コミットのみが考慮されます。 |
|
||||
| `` <c-z> `` | やり直す | 最後のgitコマンドをやり直すために実行するgitコマンドを決定するためにreflogが使用されます。これにはワーキングツリーへの変更は含まれません。コミットのみが考慮されます。 |
|
||||
|
||||
## 一覧パネルの操作
|
||||
## リストパネルのナビゲーション
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` , `` | 前のページ | |
|
||||
| `` . `` | 次のページ | |
|
||||
| `` < (<home>) `` | 最上部までスクロール | |
|
||||
| `` > (<end>) `` | 最下部までスクロール | |
|
||||
| `` < (<home>) `` | 先頭にスクロール | |
|
||||
| `` > (<end>) `` | 末尾にスクロール | |
|
||||
| `` v `` | 範囲選択を切り替え | |
|
||||
| `` <s-down> `` | Range select down | |
|
||||
| `` <s-up> `` | Range select up | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
| `` H `` | 左スクロール | |
|
||||
| `` L `` | 右スクロール | |
|
||||
| `` <s-down> `` | 範囲選択を下に | |
|
||||
| `` <s-up> `` | 範囲選択を上に | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
| `` H `` | 左にスクロール | |
|
||||
| `` L `` | 右にスクロール | |
|
||||
| `` ] `` | 次のタブ | |
|
||||
| `` [ `` | 前のタブ | |
|
||||
|
||||
## Secondary
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
|
||||
| `` <esc> `` | Exit back to side panel | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
|
||||
## Stash
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | 適用 | Apply the stash entry to your working directory. |
|
||||
| `` g `` | Pop | Apply the stash entry to your working directory and remove the stash entry. |
|
||||
| `` d `` | Drop | Remove the stash entry from the stash list. |
|
||||
| `` n `` | 新しいブランチを作成 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||
| `` r `` | Stashを変更 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | View files | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
|
||||
## Sub-commits
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` o `` | ブラウザでコミットを開く | |
|
||||
| `` n `` | コミットにブランチを作成 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | View files | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
|
||||
## Worktrees
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` n `` | New worktree | |
|
||||
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||
| `` o `` | Open in editor | |
|
||||
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
|
||||
## コミット
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||
| `` b `` | View bisect options | |
|
||||
| `` s `` | Squash | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||
| `` f `` | Fixup | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||
| `` r `` | コミットメッセージを変更 | Reword the selected commit's message. |
|
||||
| `` R `` | エディタでコミットメッセージを編集 | |
|
||||
| `` d `` | コミットを削除 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||
| `` e `` | Edit (start interactive rebase) | コミットを編集 |
|
||||
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||
| `` p `` | 選択 | Mark the selected commit to be picked (when mid-rebase). This means that the commit will be retained upon continuing the rebase. |
|
||||
| `` F `` | Fixupコミットを作成 | このコミットに対するfixupコミットを作成 |
|
||||
| `` S `` | Apply fixup commits | Squash all 'fixup!' commits, either above the selected commit, or all in current branch (autosquash). |
|
||||
| `` <c-o> `` | コミットハッシュをクリップボードにコピー | |
|
||||
| `` <c-r> `` | コピーされた(チェリーピックされた)コミットの選択をリセット | |
|
||||
| `` b `` | bisectオプションを表示 | |
|
||||
| `` s `` | スカッシュ | 選択したコミットをその下のコミットにスカッシュします。スカッシュとは複数のコミットを1つにまとめる操作です。選択したコミットのメッセージが下のコミットに追加されます。 |
|
||||
| `` f `` | フィックスアップ | 選択したコミットをその下のコミットにマージします。フィックスアップはスカッシュと似ていますが、選択したコミットのメッセージは破棄され、下のコミットのメッセージのみが保持されます。 |
|
||||
| `` r `` | メッセージ変更 | 選択したコミットのメッセージを変更します。 |
|
||||
| `` R `` | エディタでメッセージ変更 | |
|
||||
| `` d `` | 削除 | 選択したコミットを削除します。これはリベースを通じてブランチからコミットを削除します。コミットが後続のコミットが依存する変更を行っている場合、マージコンフリクトを解決する必要があるかもしれません。 |
|
||||
| `` e `` | 編集(対話型リベースを開始) | 選択したコミットを編集します。これを使用して、選択したコミットから対話型リベースを開始します。すでにリベース中の場合、これは選択したコミットを編集用にマークし、リベースを続行すると、リベースは選択したコミットで一時停止して変更を行えるようにします。 |
|
||||
| `` i `` | 対話的リベースを開始 | ブランチ上のコミットの対話的リベースを開始します。これには、HEADコミットから最初のマージコミットまたはメインブランチのコミットまでのすべてのコミットが含まれます。
|
||||
選択したコミットから対話的リベースを開始したい場合は、代わりに `e` を押してください。 |
|
||||
| `` p `` | ピック | 選択したコミットをピックするようにマークします(リベース中)。これは、リベースを続行すると、コミットが保持されることを意味します。 |
|
||||
| `` F `` | fixupコミットを作成 | 選択したコミットに対する「fixup!」コミットを作成します。fixupコミットは、選択したコミットの修正用コミットです。後で、同じコミットで `S` を押すと、上記のすべてのfixupコミットが適用されます。 |
|
||||
| `` S `` | fixupコミットを適用 | すべての「fixup!」コミットを、選択したコミットの上部または現在のブランチ内のすべてをスカッシュします(autosquash)。 |
|
||||
| `` <c-j> `` | コミットを1つ下に移動 | |
|
||||
| `` <c-k> `` | コミットを1つ上に移動 | |
|
||||
| `` V `` | コミットを貼り付け (cherry-pick) | |
|
||||
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||
| `` A `` | Amend | ステージされた変更でamendコミット |
|
||||
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
|
||||
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||
| `` T `` | タグを作成 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||
| `` <c-l> `` | ログメニューを開く | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |
|
||||
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` V `` | ペースト(チェリーピック) | |
|
||||
| `` B `` | リベース用のベースコミットとしてマーク | 次のリベース用のベースコミットを選択します。ブランチにリベースするとき、ベースコミットより上のコミットのみが持ち込まれます。これは `git rebase --onto` コマンドを使用します。 |
|
||||
| `` A `` | 修正 | ステージされた変更でコミットを修正します。選択したコミットがHEADコミットの場合、これは `git commit --amend` を実行します。それ以外の場合、コミットはリベースを通じて修正されます。 |
|
||||
| `` a `` | コミット属性を修正 | コミット作者の設定/リセットまたは共同作者の設定を行います。 |
|
||||
| `` t `` | 元に戻す | 選択したコミットの変更を逆に適用する、リバートコミットを作成します。 |
|
||||
| `` T `` | コミットにタグを付ける | 選択したコミットを指すタグを新規作成します。タグ名とオプションの説明を入力するよう促されます。 |
|
||||
| `` <c-l> `` | ログオプションを表示 | コミットログのオプションを表示します(例:並び順の変更、Gitグラフの非表示、Gitグラフ全体の表示)。 |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択したコミットをデタッチドヘッド(特定のブランチに属さない状態)としてチェックアウトします。 |
|
||||
| `` y `` | コミット属性をクリップボードにコピー | コミット属性をクリップボードにコピーします(例:ハッシュ、URL、差分、メッセージ、作者)。 |
|
||||
| `` o `` | ブラウザでコミットを開く | |
|
||||
| `` n `` | コミットにブランチを作成 | |
|
||||
| `` n `` | コミットから新しいブランチを作成 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` g `` | リセット | 選択した項目へのリセットオプション(ソフト/ミックス/ハード)を表示します。各リセットタイプの詳細は次の通りです:
|
||||
- ソフトリセット:変更を保持し、ステージされた状態にします
|
||||
- ミックスリセット:変更を保持し、ステージされていない状態にします
|
||||
- ハードリセット:すべての変更を破棄します |
|
||||
| `` C `` | コピー(チェリーピック) | コミットをコピーとしてマークします。ローカルコミットビューで `V` を押すと、コピーしたコミットをチェックアウトしたブランチにペースト(チェリーピック)できます。いつでも `<esc>` を押して選択をキャンセルできます。 |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` * `` | 現在のブランチのコミットを選択 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | View files | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
| `` <enter> `` | ファイルを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## コミットファイル
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
||||
| `` y `` | Copy to clipboard | |
|
||||
| `` c `` | チェックアウト | Checkout file. This replaces the file in your working tree with the version from the selected commit. |
|
||||
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
|
||||
| `` o `` | ファイルを開く | Open file in default application. |
|
||||
| `` e `` | 編集 | Open file in external editor. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <space> `` | Toggle file included in patch | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` <enter> `` | Enter file / Toggle directory collapsed | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||
| `` <c-o> `` | パスをクリップボードにコピー | |
|
||||
| `` y `` | クリップボードにコピー | |
|
||||
| `` c `` | チェックアウト(ブランチの切り替え) | ファイルをチェックアウトします。これにより、作業ツリー内のファイルが選択したコミットのバージョンに置き換えられます。 |
|
||||
| `` d `` | 削除 | このコミットのこのファイルへの変更を破棄します。これはバックグラウンドで対話的なリベースを実行するため、後のコミットでもこのファイルが変更されている場合、マージコンフリクトが発生する可能性があります。 |
|
||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` e `` | 編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` <space> `` | パッチに含めるファイルを切り替え | ファイルがカスタムパッチに含まれるかどうかを切り替えます。https://github.com/jesseduffield/lazygit#rebase-magic-custom-patchesを参照してください。 |
|
||||
| `` a `` | すべてのファイルを切り替え | コミットのすべてのファイルをカスタムパッチに追加/削除します。https://github.com/jesseduffield/lazygit#rebase-magic-custom-patchesを参照してください。 |
|
||||
| `` <enter> `` | ファイルに入る / ディレクトリの折りたたみを切り替える | ファイルが選択されている場合、そのファイルに入ってカスタムパッチに個々の行を追加/削除できます。ディレクトリが選択されている場合、ディレクトリを切り替えます。 |
|
||||
| `` ` `` | ファイルツリービューを切り替え | ファイルビューをフラットレイアウトとツリーレイアウトの間で切り替えます。フラットレイアウトは全てのファイルパスを単一のリストで表示し、ツリーレイアウトはディレクトリごとにファイルをグループ化します。 |
|
||||
| `` - `` | すべてのファイルを折りたたむ | ファイルツリー内のすべてのディレクトリを折りたたみます |
|
||||
| `` = `` | すべてのファイルを展開 | ファイルツリー内のすべてのディレクトリを展開します |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## コミットメッセージ
|
||||
## コミット概要
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | 確認 | |
|
||||
| `` <esc> `` | 閉じる | |
|
||||
|
||||
## サブコミット
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | コミットハッシュをクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択したコミットをデタッチドヘッド(特定のブランチに属さない状態)としてチェックアウトします。 |
|
||||
| `` y `` | コミット属性をクリップボードにコピー | コミット属性をクリップボードにコピーします(例:ハッシュ、URL、差分、メッセージ、作者)。 |
|
||||
| `` o `` | ブラウザでコミットを開く | |
|
||||
| `` n `` | コミットから新しいブランチを作成 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | リセット | 選択した項目へのリセットオプション(ソフト/ミックス/ハード)を表示します。各リセットタイプの詳細は次の通りです:
|
||||
- ソフトリセット:変更を保持し、ステージされた状態にします
|
||||
- ミックスリセット:変更を保持し、ステージされていない状態にします
|
||||
- ハードリセット:すべての変更を破棄します |
|
||||
| `` C `` | コピー(チェリーピック) | コミットをコピーとしてマークします。ローカルコミットビューで `V` を押すと、コピーしたコミットをチェックアウトしたブランチにペースト(チェリーピック)できます。いつでも `<esc>` を押して選択をキャンセルできます。 |
|
||||
| `` <c-r> `` | コピーされた(チェリーピックされた)コミットの選択をリセット | |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` * `` | 現在のブランチのコミットを選択 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | ファイルを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## サブモジュール
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | サブモジュール名をクリップボードにコピー | |
|
||||
| `` <enter> `` | Enter | サブモジュールを開く |
|
||||
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||
| `` u `` | Update | サブモジュールを更新 |
|
||||
| `` n `` | サブモジュールを新規追加 | |
|
||||
| `` e `` | サブモジュールのURLを更新 | |
|
||||
| `` i `` | Initialize | サブモジュールを初期化 |
|
||||
| `` b `` | View bulk submodule options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` <enter> `` | 入る | サブモジュールに入ります。サブモジュールに入った後、`<esc>`を押して親リポジトリに戻ることができます。 |
|
||||
| `` d `` | 削除 | 選択したサブモジュールとそれに対応するディレクトリを削除します。 |
|
||||
| `` u `` | 更新 | 選択したサブモジュールを更新します。 |
|
||||
| `` n `` | 新しいサブモジュール | |
|
||||
| `` e `` | サブモジュールURLを更新 | |
|
||||
| `` i `` | 初期化 | 選択したサブモジュールを初期化してフェッチの準備をします。おそらく、続いて「更新」アクションを呼び出してサブモジュールをフェッチしたいでしょう。 |
|
||||
| `` b `` | 一括サブモジュールオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## スタッシュ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | 適用 | スタッシュエントリをワーキングディレクトリに適用します。 |
|
||||
| `` g `` | ポップ | スタッシュエントリをワーキングディレクトリに適用し、スタッシュエントリを削除します。 |
|
||||
| `` d `` | 削除 | スタッシュリストからスタッシュエントリを削除します。 |
|
||||
| `` n `` | 新しいブランチ | 選択したスタッシュエントリから新しいブランチを作成します。これは、スタッシュエントリが作成されたコミットをgitがチェックアウトし、そのコミットから新しいブランチを作成した後、スタッシュエントリを追加のコミットとして新しいブランチに適用することで機能します。 |
|
||||
| `` r `` | スタッシュの名前を変更 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | ファイルを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## ステータス
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` o `` | 設定ファイルを開く | Open file in default application. |
|
||||
| `` e `` | 設定ファイルを編集 | Open file in external editor. |
|
||||
| `` o `` | 設定ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` e `` | 設定ファイルを編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` u `` | 更新を確認 | |
|
||||
| `` <enter> `` | 最近使用したリポジトリに切り替え | |
|
||||
| `` a `` | Show/cycle all branch logs | |
|
||||
| `` <enter> `` | 最近のリポジトリをチェックアウト | |
|
||||
| `` a `` | ブランチログの表示モードを順に切り替え | |
|
||||
|
||||
## セカンダリ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <tab> `` | ビューを切り替え | 他のビュー(ステージされた変更/ステージされていない変更)に切り替えます。 |
|
||||
| `` <esc> `` | Exit back to side panel | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## タグ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | Copy tag to clipboard | |
|
||||
| `` <space> `` | チェックアウト | Checkout the selected tag as a detached HEAD. |
|
||||
| `` n `` | タグを作成 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <c-o> `` | タグをクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択したタグをデタッチドHEADとしてチェックアウトします。 |
|
||||
| `` n `` | 新しいタグを作成 | 現在のコミットから新しいタグを作成します。タグ名とオプションの説明を入力するよう促されます。 |
|
||||
| `` d `` | 削除 | ローカル/リモートタグの削除オプションを表示します。 |
|
||||
| `` P `` | タグをプッシュ | 選択したタグをリモートにプッシュします。リモートを選択するよう促されます。 |
|
||||
| `` g `` | リセット | 選択した項目へのリセットオプション(ソフト/ミックス/ハード)を表示します。各リセットタイプの詳細は次の通りです:
|
||||
- ソフトリセット:変更を保持し、ステージされた状態にします
|
||||
- ミックスリセット:変更を保持し、ステージされていない状態にします
|
||||
- ハードリセット:すべての変更を破棄します |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | コミットを閲覧 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` <enter> `` | コミットを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## ファイル
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | ファイル名をクリップボードにコピー | |
|
||||
| `` <space> `` | ステージ/アンステージ | Toggle staged for selected file. |
|
||||
| `` <c-b> `` | ファイルをフィルタ (ステージ/アンステージ) | |
|
||||
| `` y `` | Copy to clipboard | |
|
||||
| `` c `` | 変更をコミット | Commit staged changes. |
|
||||
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
||||
| `` A `` | 最新のコミットにamend | |
|
||||
| `` C `` | gitエディタを使用して変更をコミット | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` e `` | 編集 | Open file in external editor. |
|
||||
| `` o `` | ファイルを開く | Open file in default application. |
|
||||
| `` i `` | ファイルをignore | |
|
||||
| `` r `` | ファイルをリフレッシュ | |
|
||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||
| `` S `` | View stash options | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||
| `` a `` | すべての変更をステージ/アンステージ | Toggle staged/unstaged for all files in working tree. |
|
||||
| `` <enter> `` | Stage lines / Collapse directory | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||
| `` g `` | View upstream reset options | |
|
||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||
| `` f `` | Fetch | Fetch changes from remote. |
|
||||
| `` - `` | Collapse all files | Collapse all directories in the files tree |
|
||||
| `` = `` | Expand all files | Expand all directories in the file tree |
|
||||
| `` <c-o> `` | パスをクリップボードにコピー | |
|
||||
| `` <space> `` | ステージ | 選択したファイルのステージ状態を切り替えます。 |
|
||||
| `` <c-b> `` | ステータスでファイルをフィルタリング | |
|
||||
| `` y `` | クリップボードにコピー | |
|
||||
| `` c `` | コミット | ステージされた変更をコミットします。 |
|
||||
| `` w `` | pre-commitフックなしで変更をコミット | |
|
||||
| `` A `` | 直前のコミットを修正 | |
|
||||
| `` C `` | Gitエディタを使用して変更をコミット | |
|
||||
| `` <c-f> `` | フィックスアップのベースコミットを検索 | 現在の変更が基づいているコミットを見つけて、コミットの修正/フィックスアップを行います。これにより、ブランチのコミットを一つずつ確認して、どのコミットを修正/フィックスアップすべきかを調べる手間が省けます。詳細はドキュメントを参照: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` e `` | 編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` i `` | ファイルを無視または除外 | |
|
||||
| `` r `` | ファイルを更新 | |
|
||||
| `` s `` | スタッシュ | すべての変更をスタッシュします。スタッシュの他のバリエーションについては、スタッシュオプションを表示するキーバインディングを使用してください。 |
|
||||
| `` S `` | スタッシュオプションを表示 | スタッシュオプション(すべてをスタッシュ、ステージされた変更をスタッシュ、ステージされていない変更をスタッシュなど)を表示します。 |
|
||||
| `` a `` | すべてステージ | ワーキングツリー内のすべてのファイルのステージ/アンステージを切り替えます。 |
|
||||
| `` <enter> `` | 行をステージ / ディレクトリを折りたたむ | 選択された項目がファイルの場合、個々のハンク/行をステージできるようにステージングビューにフォーカスします。選択された項目がディレクトリの場合、ディレクトリを折りたたむ/展開します。 |
|
||||
| `` d `` | 破棄 | 選択したファイルの変更を破棄するオプションを表示します。 |
|
||||
| `` g `` | アップストリームへのリセットオプションを表示 | |
|
||||
| `` D `` | リセット | 作業ツリーのリセットオプション(例:作業ツリーの完全破棄)を表示します。 |
|
||||
| `` ` `` | ファイルツリービューを切り替え | ファイルビューをフラットレイアウトとツリーレイアウトの間で切り替えます。フラットレイアウトは全てのファイルパスを単一のリストで表示し、ツリーレイアウトはディレクトリごとにファイルをグループ化します。 |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` M `` | 外部マージツールを開く | `git mergetool`を実行します。 |
|
||||
| `` f `` | フェッチ | リモートから変更をフェッチします。 |
|
||||
| `` - `` | すべてのファイルを折りたたむ | ファイルツリー内のすべてのディレクトリを折りたたみます |
|
||||
| `` = `` | すべてのファイルを展開 | ファイルツリー内のすべてのディレクトリを展開します |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## ブランチ
|
||||
## メインパネル(ステージング)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||
| `` i `` | Show git-flow options | |
|
||||
| `` <space> `` | チェックアウト | Checkout selected item. |
|
||||
| `` n `` | 新しいブランチを作成 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
| `` <left> `` | 前のハンクに移動 | |
|
||||
| `` <right> `` | 次のハンクに移動 | |
|
||||
| `` v `` | 範囲選択を切り替え | |
|
||||
| `` a `` | ハンクを選択 | ハンク選択モードを切り替えます。 |
|
||||
| `` <c-o> `` | 選択したテキストをクリップボードにコピー | |
|
||||
| `` <space> `` | ステージ | 選択された部分のステージ / アンステージを切り替えます。 |
|
||||
| `` d `` | 破棄 | ステージされていない変更が選択されている場合、`git reset`を使用して変更を破棄します。ステージされた変更が選択されている場合、変更をアンステージします。 |
|
||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` <esc> `` | ファイルパネルに戻る | |
|
||||
| `` <tab> `` | ビューを切り替え | 他のビュー(ステージされた変更/ステージされていない変更)に切り替えます。 |
|
||||
| `` E `` | ハンクを編集 | 選択したハンクを外部エディタで編集します。 |
|
||||
| `` c `` | コミット | ステージされた変更をコミットします。 |
|
||||
| `` w `` | pre-commitフックなしで変更をコミット | |
|
||||
| `` C `` | Gitエディタを使用して変更をコミット | |
|
||||
| `` <c-f> `` | フィックスアップのベースコミットを検索 | 現在の変更が基づいているコミットを見つけて、コミットの修正/フィックスアップを行います。これにより、ブランチのコミットを一つずつ確認して、どのコミットを修正/フィックスアップすべきかを調べる手間が省けます。詳細はドキュメントを参照: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` o `` | Pull Requestを作成 | |
|
||||
| `` O `` | View create pull request options | |
|
||||
| `` <c-y> `` | Pull RequestのURLをクリップボードにコピー | |
|
||||
| `` c `` | Checkout by name | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||
| `` F `` | 強制的にチェックアウト | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` f `` | Fast-forward | Fast-forward selected branch from its upstream. |
|
||||
| `` T `` | タグを作成 | |
|
||||
| `` s `` | 並び替え | |
|
||||
| `` g `` | Reset | |
|
||||
| `` R `` | ブランチ名を変更 | |
|
||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | コミットを閲覧 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
|
||||
## メインパネル (Merging)
|
||||
## メインパネル(パッチ作成)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | Pick hunk | |
|
||||
| `` b `` | Pick all hunks | |
|
||||
| `` <up> `` | 前のhunkを選択 | |
|
||||
| `` <down> `` | 次のhunkを選択 | |
|
||||
| `` <left> `` | 前のコンフリクトを選択 | |
|
||||
| `` <right> `` | 次のコンフリクトを選択 | |
|
||||
| `` z `` | アンドゥ | Undo last merge conflict resolution. |
|
||||
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||
| `` o `` | ファイルを開く | Open file in default application. |
|
||||
| `` M `` | Git mergetoolを開く | Run `git mergetool`. |
|
||||
| `` <esc> `` | ファイル一覧に戻る | |
|
||||
| `` <left> `` | 前のハンクに移動 | |
|
||||
| `` <right> `` | 次のハンクに移動 | |
|
||||
| `` v `` | 範囲選択を切り替え | |
|
||||
| `` a `` | ハンクを選択 | ハンク選択モードを切り替えます。 |
|
||||
| `` <c-o> `` | 選択したテキストをクリップボードにコピー | |
|
||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` <space> `` | パッチ内の行を切り替え | |
|
||||
| `` <esc> `` | カスタムパッチビルダーを終了 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## メインパネル (Normal)
|
||||
## メインパネル(マージ中)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | ハンクを選択 | |
|
||||
| `` b `` | すべてのハンクを選択 | |
|
||||
| `` <up> `` | 前のハンク | |
|
||||
| `` <down> `` | 次のハンク | |
|
||||
| `` <left> `` | 前のコンフリクト | |
|
||||
| `` <right> `` | 次のコンフリクト | |
|
||||
| `` z `` | 元に戻す | 最後のマージコンフリクト解決を元に戻します。 |
|
||||
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
|
||||
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
|
||||
| `` M `` | 外部マージツールを開く | `git mergetool`を実行します。 |
|
||||
| `` <esc> `` | ファイルパネルに戻る | |
|
||||
|
||||
## メインパネル(通常)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` mouse wheel down (fn+up) `` | 下にスクロール | |
|
||||
| `` mouse wheel up (fn+down) `` | 上にスクロール | |
|
||||
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
|
||||
| `` <tab> `` | ビューを切り替え | 他のビュー(ステージされた変更/ステージされていない変更)に切り替えます。 |
|
||||
| `` <esc> `` | Exit back to side panel | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
|
||||
## メインパネル (Patch Building)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <left> `` | 前のhunkを選択 | |
|
||||
| `` <right> `` | 次のhunkを選択 | |
|
||||
| `` v `` | 範囲選択を切り替え | |
|
||||
| `` a `` | Hunk選択を切り替え | Toggle hunk selection mode. |
|
||||
| `` <c-o> `` | 選択されたテキストをクリップボードにコピー | |
|
||||
| `` o `` | ファイルを開く | Open file in default application. |
|
||||
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||
| `` <space> `` | 行をパッチに追加/削除 | |
|
||||
| `` <esc> `` | Exit custom patch builder | |
|
||||
| `` / `` | 検索を開始 | |
|
||||
|
||||
## メインパネル (Staging)
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <left> `` | 前のhunkを選択 | |
|
||||
| `` <right> `` | 次のhunkを選択 | |
|
||||
| `` v `` | 範囲選択を切り替え | |
|
||||
| `` a `` | Hunk選択を切り替え | Toggle hunk selection mode. |
|
||||
| `` <c-o> `` | 選択されたテキストをクリップボードにコピー | |
|
||||
| `` <space> `` | ステージ/アンステージ | 選択行をステージ/アンステージ |
|
||||
| `` d `` | 変更を削除 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
|
||||
| `` o `` | ファイルを開く | Open file in default application. |
|
||||
| `` e `` | ファイルを編集 | Open file in external editor. |
|
||||
| `` <esc> `` | ファイル一覧に戻る | |
|
||||
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
|
||||
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||
| `` c `` | 変更をコミット | Commit staged changes. |
|
||||
| `` w `` | pre-commitフックを実行せずに変更をコミット | |
|
||||
| `` C `` | gitエディタを使用して変更をコミット | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` / `` | 検索を開始 | |
|
||||
| `` / `` | 現在のビューをテキストで検索 | |
|
||||
|
||||
## メニュー
|
||||
|
||||
@@ -348,59 +316,106 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | 実行 | |
|
||||
| `` <esc> `` | 閉じる | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## リフログ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | コミットハッシュをクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択したコミットをデタッチドヘッド(特定のブランチに属さない状態)としてチェックアウトします。 |
|
||||
| `` y `` | コミット属性をクリップボードにコピー | コミット属性をクリップボードにコピーします(例:ハッシュ、URL、差分、メッセージ、作者)。 |
|
||||
| `` o `` | ブラウザでコミットを開く | |
|
||||
| `` n `` | コミットから新しいブランチを作成 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | リセット | 選択した項目へのリセットオプション(ソフト/ミックス/ハード)を表示します。各リセットタイプの詳細は次の通りです:
|
||||
- ソフトリセット:変更を保持し、ステージされた状態にします
|
||||
- ミックスリセット:変更を保持し、ステージされていない状態にします
|
||||
- ハードリセット:すべての変更を破棄します |
|
||||
| `` C `` | コピー(チェリーピック) | コミットをコピーとしてマークします。ローカルコミットビューで `V` を押すと、コピーしたコミットをチェックアウトしたブランチにペースト(チェリーピック)できます。いつでも `<esc>` を押して選択をキャンセルできます。 |
|
||||
| `` <c-r> `` | コピーされた(チェリーピックされた)コミットの選択をリセット | |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` * `` | 現在のブランチのコミットを選択 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | コミットを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## リモート
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | View branches | |
|
||||
| `` n `` | リモートを新規追加 | |
|
||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||
| `` e `` | 編集 | リモートを編集 |
|
||||
| `` f `` | Fetch | リモートをfetch |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` <enter> `` | ブランチを表示 | |
|
||||
| `` n `` | 新しいリモート | |
|
||||
| `` d `` | 削除 | 選択したリモートを削除します。そのリモートからのリモートブランチを追跡しているローカルブランチは影響を受けません。 |
|
||||
| `` e `` | 編集 | 選択したリモートの名前またはURLを編集します。 |
|
||||
| `` f `` | フェッチ | リモートリポジトリから更新をフェッチします。これにより、ローカルブランチにマージせずに新しいコミットとブランチを取得します。 |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## リモートブランチ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト | Checkout a new local branch based on the selected remote branch, or the remote branch as a detached head. |
|
||||
| `` n `` | 新しいブランチを作成 | |
|
||||
| `` M `` | 現在のブランチにマージ | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` r `` | Rebase | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||
| `` u `` | Set as upstream | Set the selected remote branch as the upstream of the checked-out branch. |
|
||||
| `` s `` | 並び替え | |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択したリモートブランチに基づいて新しいローカルブランチをチェックアウトするか、リモートブランチをデタッチドヘッドとしてチェックアウトします。 |
|
||||
| `` n `` | 新しいブランチ | |
|
||||
| `` M `` | マージ | 選択した項目を現在のブランチにマージするためのオプションを表示します(通常のマージ、スカッシュマージ) |
|
||||
| `` r `` | リベース | チェックアウトしたブランチを選択したブランチ上にリベースします。 |
|
||||
| `` d `` | 削除 | リモートからリモートブランチを削除します。 |
|
||||
| `` u `` | アップストリームとして設定 | 選択したリモートブランチをチェックアウトされたブランチのアップストリームとして設定します。 |
|
||||
| `` s `` | 並び順 | |
|
||||
| `` g `` | リセット | 選択した項目へのリセットオプション(ソフト/ミックス/ハード)を表示します。各リセットタイプの詳細は次の通りです:
|
||||
- ソフトリセット:変更を保持し、ステージされた状態にします
|
||||
- ミックスリセット:変更を保持し、ステージされていない状態にします
|
||||
- ハードリセット:すべての変更を破棄します |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | コミットを閲覧 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` <enter> `` | コミットを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## 参照ログ
|
||||
## ローカルブランチ
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | コミットのhashをクリップボードにコピー | |
|
||||
| `` <space> `` | チェックアウト | Checkout the selected commit as a detached HEAD. |
|
||||
| `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` o `` | ブラウザでコミットを開く | |
|
||||
| `` n `` | コミットにブランチを作成 | |
|
||||
| `` <c-o> `` | ブランチ名をクリップボードにコピー | |
|
||||
| `` i `` | git-flowオプションを表示 | |
|
||||
| `` <space> `` | チェックアウト(ブランチの切り替え) | 選択した項目をチェックアウトします。 |
|
||||
| `` n `` | 新しいブランチ | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` o `` | プルリクエストを作成 | |
|
||||
| `` O `` | プルリクエスト作成オプションを表示 | |
|
||||
| `` <c-y> `` | プルリクエストURLをクリップボードにコピー | |
|
||||
| `` c `` | 名前でチェックアウト | 名前でチェックアウトします。入力ボックスに「-」を入力すると、最後のブランチをチェックアウトすることができます。 |
|
||||
| `` F `` | 強制チェックアウト | 選択したブランチを強制的にチェックアウトします。これにより、選択したブランチをチェックアウトする前にワーキングディレクトリ内のすべてのローカル変更が破棄されます。 |
|
||||
| `` d `` | 削除 | ローカル/リモートブランチの削除オプションを表示します。 |
|
||||
| `` r `` | リベース | チェックアウトしたブランチを選択したブランチ上にリベースします。 |
|
||||
| `` M `` | マージ | 選択した項目を現在のブランチにマージするためのオプションを表示します(通常のマージ、スカッシュマージ) |
|
||||
| `` f `` | ブランチを最新化(fast-forward) | 選択したブランチを対応するアップストリームの最新状態に追いつかせます(fast-forward)。 |
|
||||
| `` T `` | 新しいタグを作成 | |
|
||||
| `` s `` | 並び順 | |
|
||||
| `` g `` | リセット | |
|
||||
| `` R `` | ブランチ名を変更 | |
|
||||
| `` u `` | アップストリームオプションを表示 | ブランチのアップストリームに関連するオプションを表示します(例:アップストリームの設定/解除やアップストリームへのリセット)。 |
|
||||
| `` <c-t> `` | 外部差分ツールを開く(git difftool) | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | コミットを閲覧 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` <enter> `` | コミットを表示 | |
|
||||
| `` w `` | ワークツリーオプションを表示 | |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## ワークツリー
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` n `` | 新しいワークツリー | |
|
||||
| `` <space> `` | チェックアウト(切り替え) | 選択したワークツリーをチェックアウト(切り替え)します。 |
|
||||
| `` o `` | エディタで開く | |
|
||||
| `` d `` | 削除 | 選択したワークツリーを削除します。これはワークツリーのディレクトリとワークツリーに関するメタデータの両方を.gitディレクトリから削除します。 |
|
||||
| `` / `` | 現在のビューをテキストでフィルタリング | |
|
||||
|
||||
## 確認パネル
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Veja a documentação:
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | Copy branch name to clipboard | |
|
||||
| `` i `` | Show git-flow options | |
|
||||
| `` i `` | Exibir opções do git-flow | |
|
||||
| `` <space> `` | Verificar | Checar item selecionado |
|
||||
| `` n `` | Nova branch | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
@@ -12,15 +12,15 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
||||
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
|
||||
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
|
||||
| `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 |
|
||||
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,你可以在弹窗中配置上游分支。 |
|
||||
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游未配置,你可以在弹窗中配置上游分支。 |
|
||||
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游未配置,您可以在弹窗中配置上游分支。 |
|
||||
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游未配置,您可以在弹窗中配置上游分支。 |
|
||||
| `` ) `` | 提高重命名相似度阈值 | 增加删除和添加对被视作重命名的相似度阈值。 |
|
||||
| `` ( `` | 降低重命名相似度阈值 | 降低删除和添加对被视作重命名的相似度阈值。 |
|
||||
| `` } `` | 扩大差异视图中显示的上下文范围 | 增加diff视图中围绕更改显示的上下文数量 |
|
||||
| `` { `` | 缩小差异视图中显示的上下文范围 | 减少diff视图中围绕更改显示的上下文数量 |
|
||||
| `` : `` | 执行 Shell 命令 | Bring up a prompt where you can enter a shell command to execute. |
|
||||
| `` : `` | 执行 Shell 命令 | 调出可输入shell命令执行的提示符。 |
|
||||
| `` <c-p> `` | 查看自定义补丁选项 | |
|
||||
| `` m `` | 查看 合并/变基 选项 | 查看当前合并或变基的中止、继续、跳过选项 |
|
||||
| `` m `` | 查看合并/变基选项 | 查看当前合并或变基的中止、继续、跳过选项 |
|
||||
| `` R `` | 刷新 | 刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch` |
|
||||
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||
| `` _ `` | 上一屏模式 | |
|
||||
@@ -55,19 +55,19 @@ _图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制提交哈希到剪贴板 | |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(如hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,您可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` * `` | 选择当前分支的提交 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | 查看提交 | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
@@ -77,19 +77,19 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制提交哈希到剪贴板 | |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(如hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,您可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` * `` | 选择当前分支的提交 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | 查看提交的文件 | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
@@ -99,7 +99,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制子模块名称到剪贴板 | |
|
||||
| `` <enter> `` | 进入 | 输入子模块 |
|
||||
| `` d `` | 删除 | 删除选定的子模块及其相应的目录 |
|
||||
| `` u `` | 更新 | 更新子模块 |
|
||||
@@ -123,7 +123,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制提交哈希到剪贴板 | |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` b `` | 查看二分查找选项 | |
|
||||
| `` s `` | 压缩(Squash) | 将已选提交压缩到该提交之下。这些选定的提交的消息会附加到该提交的消息之下。 |
|
||||
@@ -144,19 +144,19 @@ Note that this disregards the selection, the new branch is always created either
|
||||
| `` A `` | 修补(Amend) | 用已暂存的变更来修补提交 |
|
||||
| `` a `` | 修补提交属性 | 设置或重置提交的作者,或添加其他作者。 |
|
||||
| `` t `` | 撤销(Revert) | 为所选提交创建还原提交,这会反向应用所选提交的更改。 |
|
||||
| `` T `` | 标签提交 | 创建一个新标签指向所选提交。你可以在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` T `` | 标签提交 | 创建一个新标签指向所选提交。您可以在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` <c-l> `` | 打开日志菜单 | 查看提交日志的选项,例如更改排序顺序、隐藏 git graph、显示整个 git graph。 |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(如hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.
|
||||
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,您可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` * `` | Select commits of current branch | |
|
||||
| `` * `` | 选择当前分支的提交 | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
| `` <enter> `` | 查看提交的文件 | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
@@ -173,7 +173,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制路径到剪贴板 | |
|
||||
| `` y `` | 复制到剪贴板 | |
|
||||
| `` c `` | 检出 | 检出文件 |
|
||||
| `` d `` | 删除 | 放弃对此文件的提交变更 |
|
||||
@@ -193,7 +193,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制路径到剪贴板 | |
|
||||
| `` <space> `` | 切换暂存状态 | 为选定的文件切换暂存状态 |
|
||||
| `` <c-b> `` | 通过状态过滤文件 | |
|
||||
| `` y `` | 复制到剪贴板 | |
|
||||
@@ -226,7 +226,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制分支名称到剪贴板 | |
|
||||
| `` i `` | 显示 git-flow 选项 | |
|
||||
| `` <space> `` | 检出 | 检出选中的项目 |
|
||||
| `` n `` | 新分支 | |
|
||||
@@ -235,11 +235,11 @@ Note that this disregards the selection, the new branch is always created either
|
||||
Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). |
|
||||
| `` o `` | 创建拉取请求 | |
|
||||
| `` O `` | 创建拉取请求选项 | |
|
||||
| `` <c-y> `` | 将拉取请求 URL 复制到剪贴板 | |
|
||||
| `` <c-y> `` | 复制拉取请求 URL 到剪贴板 | |
|
||||
| `` c `` | 按名称检出 | 按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。 |
|
||||
| `` F `` | 强制检出 | 强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。 |
|
||||
| `` d `` | 删除 | 查看本地/远程分支的删除选项 |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` r `` | 变基 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||
| `` f `` | 从上游快进此分支 | 将当前分支直接移动到远程追踪分支的最新提交 |
|
||||
| `` T `` | 创建标签 | |
|
||||
@@ -261,7 +261,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
| `` <right> `` | 选择下一个区块 | |
|
||||
| `` v `` | 切换拖动选择 | |
|
||||
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制选中文本到剪贴板 | |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||
| `` <space> `` | 添加/移除 行到补丁 | |
|
||||
@@ -272,11 +272,11 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将标签复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制标签到剪贴板 | |
|
||||
| `` <space> `` | 检出 | 检出选择的标签作为分离的HEAD |
|
||||
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。您将在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` d `` | 删除 | 查看本地/远程标签的删除选项 |
|
||||
| `` P `` | 推送标签 | 推送选择的标签到远端。你将在弹窗中选择一个远端。 |
|
||||
| `` P `` | 推送标签 | 推送选择的标签到远端。您将在弹窗中选择一个远端。 |
|
||||
| `` g `` | 重置 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` 0 `` | Focus main view | |
|
||||
@@ -316,7 +316,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
| `` <right> `` | 选择下一个区块 | |
|
||||
| `` v `` | 切换拖动选择 | |
|
||||
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制选中文本到剪贴板 | |
|
||||
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
|
||||
| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
@@ -348,7 +348,7 @@ Note that this disregards the selection, the new branch is always created either
|
||||
| `` e `` | 编辑配置文件 | 使用外部编辑器打开文件 |
|
||||
| `` u `` | 检查更新 | |
|
||||
| `` <enter> `` | 切换到最近的仓库 | |
|
||||
| `` a `` | Show/cycle all branch logs | |
|
||||
| `` a `` | 显示/循环所有分支日志 | |
|
||||
|
||||
## 确认面板
|
||||
|
||||
@@ -394,11 +394,11 @@ Note that this disregards the selection, the new branch is always created either
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||
| `` <c-o> `` | 复制分支名称到剪贴板 | |
|
||||
| `` <space> `` | 检出 | 基于当前选中的远程分支检出一个新的本地分支,或者将远程分支作分离的HEAD。 |
|
||||
| `` n `` | 新分支 | |
|
||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` r `` | 变基 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` d `` | 删除 | 从远程删除远程分支。 |
|
||||
| `` u `` | 设置为上游 | 设置为检出分支的上游 |
|
||||
| `` s `` | 排序 | |
|
||||
|
||||
@@ -47,7 +47,7 @@ require (
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
|
||||
@@ -65,8 +65,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:tuijfIjZyjZaHq9xDUh0tNitwXshJpbLkqMOJv4H3do=
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:po7NpZ/QiTKzBKyrsEAxwnTamCoh8uDk/egRpQ7siIc=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
|
||||
+2
-2
@@ -86,9 +86,9 @@ func newLogger(cfg config.AppConfigurer) *logrus.Entry {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return logs.NewDevelopmentLogger(logPath)
|
||||
} else {
|
||||
return logs.NewProductionLogger()
|
||||
}
|
||||
|
||||
return logs.NewProductionLogger()
|
||||
}
|
||||
|
||||
// NewApp bootstrap a new application
|
||||
|
||||
@@ -21,9 +21,8 @@ type TodoLine struct {
|
||||
func (self *TodoLine) ToString() string {
|
||||
if self.Action == "break" {
|
||||
return self.Action + "\n"
|
||||
} else {
|
||||
return self.Action + " " + self.Commit.Hash() + " " + self.Commit.Name + "\n"
|
||||
}
|
||||
return self.Action + " " + self.Commit.Hash() + " " + self.Commit.Name + "\n"
|
||||
}
|
||||
|
||||
func TodoLinesToString(todoLines []TodoLine) string {
|
||||
|
||||
@@ -28,7 +28,7 @@ func (self *gitCmdObjRunner) Run(cmdObj *oscommands.CmdObj) error {
|
||||
func (self *gitCmdObjRunner) RunWithOutput(cmdObj *oscommands.CmdObj) (string, error) {
|
||||
var output string
|
||||
var err error
|
||||
for i := 0; i < RetryCount; i++ {
|
||||
for range RetryCount {
|
||||
newCmdObj := cmdObj.Clone()
|
||||
output, err = self.innerRunner.RunWithOutput(newCmdObj)
|
||||
|
||||
@@ -47,7 +47,7 @@ func (self *gitCmdObjRunner) RunWithOutput(cmdObj *oscommands.CmdObj) (string, e
|
||||
func (self *gitCmdObjRunner) RunWithOutputs(cmdObj *oscommands.CmdObj) (string, string, error) {
|
||||
var stdout, stderr string
|
||||
var err error
|
||||
for i := 0; i < RetryCount; i++ {
|
||||
for range RetryCount {
|
||||
newCmdObj := cmdObj.Clone()
|
||||
stdout, stderr, err = self.innerRunner.RunWithOutputs(newCmdObj)
|
||||
|
||||
|
||||
@@ -102,19 +102,18 @@ func (self *BranchCommands) CurrentBranchInfo() (BranchInfo, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CurrentBranchName get name of current branch
|
||||
// CurrentBranchName get name of current branch. Returns empty string if HEAD is detached.
|
||||
func (self *BranchCommands) CurrentBranchName() (string, error) {
|
||||
cmdArgs := NewGitCmd("rev-parse").
|
||||
Arg("--abbrev-ref").
|
||||
Arg("--verify").
|
||||
Arg("HEAD").
|
||||
cmdArgs := NewGitCmd("branch").
|
||||
Arg("--show-current").
|
||||
ToArgv()
|
||||
|
||||
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
if err == nil {
|
||||
return strings.TrimSpace(output), nil
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", err
|
||||
|
||||
return strings.TrimSpace(output), nil
|
||||
}
|
||||
|
||||
// LocalDelete delete branch locally
|
||||
|
||||
@@ -356,9 +356,8 @@ func parseDifference(track string, regexStr string) string {
|
||||
match := re.FindStringSubmatch(track)
|
||||
if len(match) > 1 {
|
||||
return match[1]
|
||||
} else {
|
||||
return "0"
|
||||
}
|
||||
return "0"
|
||||
}
|
||||
|
||||
// TODO: only look at the new reflog commits, and otherwise store the recencies in
|
||||
|
||||
@@ -149,9 +149,8 @@ func (self *CommitCommands) CommitEditorCmdObj() *oscommands.CmdObj {
|
||||
func (self *CommitCommands) signoffFlag() string {
|
||||
if self.UserConfig().Git.Commit.SignOff {
|
||||
return "--signoff"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *CommitCommands) GetCommitMessage(commitHash string) (string, error) {
|
||||
|
||||
@@ -16,16 +16,16 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var commitsOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode
|
||||
var commitsOutput = strings.ReplaceAll(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode
|
||||
b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield|jessedduffield@gmail.com|origin/better-tests|e94e8fc5b6fab4cb755f|>|fix logging
|
||||
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield|jessedduffield@gmail.com|tag: 123, tag: 456|d8084cd558925eb7c9c3|>|refactor
|
||||
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield|jessedduffield@gmail.com||65f910ebd85283b5cce9|>|WIP
|
||||
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield|jessedduffield@gmail.com||26c07b1ab33860a1a759|>|WIP
|
||||
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield|jessedduffield@gmail.com||3d4470a6c072208722e5|>|WIP
|
||||
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield|jessedduffield@gmail.com||053a66a7be3da43aacdc|>|WIP
|
||||
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|>|refactoring the config struct`, "|", "\x00", -1)
|
||||
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield|jessedduffield@gmail.com||985fe482e806b172aea4|>|refactoring the config struct`, "|", "\x00")
|
||||
|
||||
var singleCommitOutput = strings.Replace(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode`, "|", "\x00", -1)
|
||||
var singleCommitOutput = strings.ReplaceAll(`0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield|jessedduffield@gmail.com|HEAD -> better-tests|b21997d6b4cbdf84b149|>|better typing for rebase mode`, "|", "\x00")
|
||||
|
||||
func TestGetCommits(t *testing.T) {
|
||||
type scenario struct {
|
||||
|
||||
@@ -97,7 +97,7 @@ func buildGitCommon(deps commonDeps) *GitCommon {
|
||||
|
||||
func buildRepo() *gogit.Repository {
|
||||
// TODO: think of a way to actually mock this out
|
||||
var repo *gogit.Repository = nil
|
||||
var repo *gogit.Repository
|
||||
return repo
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ type FileDiff struct {
|
||||
LinesDeleted int
|
||||
}
|
||||
|
||||
func (fileLoader *FileLoader) getFileDiffs() (map[string]FileDiff, error) {
|
||||
diffs, err := fileLoader.gitDiffNumStat()
|
||||
func (self *FileLoader) getFileDiffs() (map[string]FileDiff, error) {
|
||||
diffs, err := self.gitDiffNumStat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -157,8 +157,8 @@ type FileStatus struct {
|
||||
PreviousPath string
|
||||
}
|
||||
|
||||
func (fileLoader *FileLoader) gitDiffNumStat() (string, error) {
|
||||
return fileLoader.cmd.New(
|
||||
func (self *FileLoader) gitDiffNumStat() (string, error) {
|
||||
return self.cmd.New(
|
||||
NewGitCmd("diff").
|
||||
Arg("--numstat").
|
||||
Arg("-z").
|
||||
|
||||
@@ -32,9 +32,8 @@ func (self *GitCommandBuilder) ArgIf(condition bool, ifTrue ...string) *GitComma
|
||||
func (self *GitCommandBuilder) ArgIfElse(condition bool, ifTrue string, ifFalse string) *GitCommandBuilder {
|
||||
if condition {
|
||||
return self.Arg(ifTrue)
|
||||
} else {
|
||||
return self.Arg(ifFalse)
|
||||
}
|
||||
return self.Arg(ifFalse)
|
||||
}
|
||||
|
||||
func (self *GitCommandBuilder) Config(value string) *GitCommandBuilder {
|
||||
|
||||
@@ -21,7 +21,7 @@ type MainBranches struct {
|
||||
previousMainBranches []string
|
||||
|
||||
cmd oscommands.ICmdObjBuilder
|
||||
mutex *deadlock.Mutex
|
||||
mutex deadlock.Mutex
|
||||
}
|
||||
|
||||
func NewMainBranches(
|
||||
@@ -32,7 +32,6 @@ func NewMainBranches(
|
||||
c: cmn,
|
||||
existingMainBranches: nil,
|
||||
cmd: cmd,
|
||||
mutex: &deadlock.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package git_commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
@@ -162,7 +163,7 @@ func (self *PatchCommands) MovePatchToSelectedCommit(commits []*models.Commit, s
|
||||
self.os.LogCommand(logTodoChanges(changes), false)
|
||||
|
||||
err := self.rebase.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: commits[baseIndex].Hash(),
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, baseIndex),
|
||||
overrideEditor: true,
|
||||
instruction: daemon.NewChangeTodoActionsInstruction(changes),
|
||||
}).Run()
|
||||
@@ -218,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].Hash()); err != nil {
|
||||
if err := self.stash.Push(fmt.Sprintf(self.Tr.AutoStashForMovingPatchToIndex, commits[commitIdx].ShortHash())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -259,7 +260,7 @@ func (self *PatchCommands) MovePatchIntoIndex(commits []*models.Commit, commitId
|
||||
}
|
||||
|
||||
if stash {
|
||||
if err := self.stash.Apply(0); err != nil {
|
||||
if err := self.stash.Pop(0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ func NewRebaseCommands(
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
|
||||
// This check is currently unreachable (handled in LocalCommitsController.reword),
|
||||
// but kept as a safeguard in case this method is used elsewhere.
|
||||
if self.config.NeedsGpgSubprocessForCommit() {
|
||||
return errors.New(self.Tr.DisabledForGPG)
|
||||
}
|
||||
@@ -325,9 +327,8 @@ func (self *RebaseCommands) MoveFixupCommitDown(commits []*models.Commit, target
|
||||
func todoFromCommit(commit *models.Commit) utils.Todo {
|
||||
if commit.Action == todo.UpdateRef {
|
||||
return utils.Todo{Ref: commit.Name}
|
||||
} else {
|
||||
return utils.Todo{Hash: commit.Hash()}
|
||||
}
|
||||
return utils.Todo{Hash: commit.Hash()}
|
||||
}
|
||||
|
||||
// Sets the action for the given commits in the git-rebase-todo file
|
||||
@@ -410,9 +411,9 @@ func (self *RebaseCommands) BeginInteractiveRebaseForCommit(
|
||||
instruction: daemon.NewInsertBreakInstruction(),
|
||||
keepCommitsThatBecomeEmpty: keepCommitsThatBecomeEmpty,
|
||||
}).Run()
|
||||
} else {
|
||||
return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty)
|
||||
}
|
||||
|
||||
return self.BeginInteractiveRebaseForCommitRange(commits, commitIndex, commitIndex, keepCommitsThatBecomeEmpty)
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) BeginInteractiveRebaseForCommitRange(
|
||||
@@ -572,7 +573,7 @@ func getBaseHashOrRoot(commits []*models.Commit, index int) string {
|
||||
// at time of writing)
|
||||
if index < len(commits) {
|
||||
return commits[index].Hash()
|
||||
} else {
|
||||
return "--root"
|
||||
}
|
||||
|
||||
return "--root"
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var reflogOutput = strings.Replace(`c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1
|
||||
var reflogOutput = strings.ReplaceAll(`c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1
|
||||
c3c4b66b64c97ffeecde|1643150483|checkout: moving from B to A|51baa8c1
|
||||
c3c4b66b64c97ffeecde|1643150483|checkout: moving from A to B|51baa8c1
|
||||
c3c4b66b64c97ffeecde|1643150483|checkout: moving from master to A|51baa8c1
|
||||
f4ddf2f0d4be4ccc7efa|1643149435|checkout: moving from A to master|51baa8c1
|
||||
`, "|", "\x00", -1)
|
||||
`, "|", "\x00")
|
||||
|
||||
func TestGetReflogCommits(t *testing.T) {
|
||||
type scenario struct {
|
||||
|
||||
@@ -21,7 +21,7 @@ type RepoPaths struct {
|
||||
isBareRepo bool
|
||||
}
|
||||
|
||||
var gitPathFormatVersion GitVersion = GitVersion{2, 31, 0, ""}
|
||||
var gitPathFormatVersion = GitVersion{2, 31, 0, ""}
|
||||
|
||||
// Path to the current worktree. If we're in the main worktree, this will
|
||||
// be the same as RepoPath()
|
||||
|
||||
@@ -184,9 +184,7 @@ func TestGetRepoPaths(t *testing.T) {
|
||||
Expected: nil,
|
||||
Err: func(getRevParseArgs argFn) error {
|
||||
args := strings.Join(getRevParseArgs(), " ")
|
||||
return errors.New(
|
||||
fmt.Sprintf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args),
|
||||
)
|
||||
return fmt.Errorf("'git %v --show-toplevel --absolute-git-dir --git-common-dir --is-bare-repository --show-superproject-working-tree' failed: fatal: invalid gitfile format: /path/to/repo/worktree2/.git", args)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,21 +32,21 @@ func (self *StashCommands) DropNewest() error {
|
||||
}
|
||||
|
||||
func (self *StashCommands) Drop(index int) error {
|
||||
cmdArgs := NewGitCmd("stash").Arg("drop", fmt.Sprintf("stash@{%d}", index)).
|
||||
cmdArgs := NewGitCmd("stash").Arg("drop", fmt.Sprintf("refs/stash@{%d}", index)).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).Run()
|
||||
}
|
||||
|
||||
func (self *StashCommands) Pop(index int) error {
|
||||
cmdArgs := NewGitCmd("stash").Arg("pop", fmt.Sprintf("stash@{%d}", index)).
|
||||
cmdArgs := NewGitCmd("stash").Arg("pop", fmt.Sprintf("refs/stash@{%d}", index)).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).Run()
|
||||
}
|
||||
|
||||
func (self *StashCommands) Apply(index int) error {
|
||||
cmdArgs := NewGitCmd("stash").Arg("apply", fmt.Sprintf("stash@{%d}", index)).
|
||||
cmdArgs := NewGitCmd("stash").Arg("apply", fmt.Sprintf("refs/stash@{%d}", index)).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).Run()
|
||||
@@ -90,7 +90,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj {
|
||||
Arg(fmt.Sprintf("--unified=%d", self.AppState.DiffContextSize)).
|
||||
ArgIf(self.AppState.IgnoreWhitespaceInDiffView, "--ignore-all-space").
|
||||
Arg(fmt.Sprintf("--find-renames=%d%%", self.AppState.RenameSimilarityThreshold)).
|
||||
Arg(fmt.Sprintf("stash@{%d}", index)).
|
||||
Arg(fmt.Sprintf("refs/stash@{%d}", index)).
|
||||
Dir(self.repoPaths.worktreePath).
|
||||
ToArgv()
|
||||
|
||||
@@ -152,7 +152,7 @@ func (self *StashCommands) SaveStagedChanges(message string) error {
|
||||
}
|
||||
|
||||
if err := self.cmd.New(
|
||||
NewGitCmd("stash").Arg("apply", "stash@{1}").ToArgv(),
|
||||
NewGitCmd("stash").Arg("apply", "refs/stash@{1}").ToArgv(),
|
||||
).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func (self *StashCommands) SaveStagedChanges(message string) error {
|
||||
}
|
||||
|
||||
if err := self.cmd.New(
|
||||
NewGitCmd("stash").Arg("drop", "stash@{1}").ToArgv(),
|
||||
NewGitCmd("stash").Arg("drop", "refs/stash@{1}").ToArgv(),
|
||||
).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ outer:
|
||||
if err != nil {
|
||||
return self.getUnfilteredStashEntries()
|
||||
}
|
||||
currentStashEntry = self.stashEntryFromLine(lines[i], idx)
|
||||
currentStashEntry = stashEntryFromLine(lines[i], idx)
|
||||
for i+1 < len(lines) && !isAStash(lines[i+1]) {
|
||||
i++
|
||||
if lines[i] == filterPath {
|
||||
@@ -70,11 +70,11 @@ func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry {
|
||||
|
||||
rawString, _ := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
return lo.Map(utils.SplitNul(rawString), func(line string, index int) *models.StashEntry {
|
||||
return self.stashEntryFromLine(line, index)
|
||||
return stashEntryFromLine(line, index)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry {
|
||||
func stashEntryFromLine(line string, index int) *models.StashEntry {
|
||||
model := &models.StashEntry{
|
||||
Name: line,
|
||||
Index: index,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestStashDrop(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"stash", "drop", "stash@{1}"}, "Dropped refs/stash@{1} (98e9cca532c37c766107093010c72e26f2c24c04)\n", nil)
|
||||
ExpectGitArgs([]string{"stash", "drop", "refs/stash@{1}"}, "Dropped refs/stash@{1} (98e9cca532c37c766107093010c72e26f2c24c04)\n", nil)
|
||||
instance := buildStashCommands(commonDeps{runner: runner})
|
||||
|
||||
assert.NoError(t, instance.Drop(1))
|
||||
@@ -19,7 +19,7 @@ func TestStashDrop(t *testing.T) {
|
||||
|
||||
func TestStashApply(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"stash", "apply", "stash@{1}"}, "", nil)
|
||||
ExpectGitArgs([]string{"stash", "apply", "refs/stash@{1}"}, "", nil)
|
||||
instance := buildStashCommands(commonDeps{runner: runner})
|
||||
|
||||
assert.NoError(t, instance.Apply(1))
|
||||
@@ -28,7 +28,7 @@ func TestStashApply(t *testing.T) {
|
||||
|
||||
func TestStashPop(t *testing.T) {
|
||||
runner := oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"stash", "pop", "stash@{1}"}, "", nil)
|
||||
ExpectGitArgs([]string{"stash", "pop", "refs/stash@{1}"}, "", nil)
|
||||
instance := buildStashCommands(commonDeps{runner: runner})
|
||||
|
||||
assert.NoError(t, instance.Pop(1))
|
||||
@@ -113,7 +113,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
contextSize: 3,
|
||||
similarityThreshold: 50,
|
||||
ignoreWhitespace: false,
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=50%", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=50%", "refs/stash@{5}"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom context size",
|
||||
@@ -121,7 +121,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
contextSize: 77,
|
||||
similarityThreshold: 50,
|
||||
ignoreWhitespace: false,
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=77", "--find-renames=50%", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=77", "--find-renames=50%", "refs/stash@{5}"},
|
||||
},
|
||||
{
|
||||
testName: "Show diff with custom similarity threshold",
|
||||
@@ -129,7 +129,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
contextSize: 3,
|
||||
similarityThreshold: 33,
|
||||
ignoreWhitespace: false,
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=33%", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--find-renames=33%", "refs/stash@{5}"},
|
||||
},
|
||||
{
|
||||
testName: "Default case",
|
||||
@@ -137,7 +137,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
contextSize: 3,
|
||||
similarityThreshold: 50,
|
||||
ignoreWhitespace: true,
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "stash@{5}"},
|
||||
expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--color=always", "--unified=3", "--ignore-all-space", "--find-renames=50%", "refs/stash@{5}"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ func TestStashRename(t *testing.T) {
|
||||
message: "New message",
|
||||
expectedHashCmd: []string{"rev-parse", "refs/stash@{3}"},
|
||||
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
||||
expectedDropCmd: []string{"stash", "drop", "stash@{3}"},
|
||||
expectedDropCmd: []string{"stash", "drop", "refs/stash@{3}"},
|
||||
expectedStoreCmd: []string{"stash", "store", "-m", "New message", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
||||
},
|
||||
{
|
||||
@@ -186,7 +186,7 @@ func TestStashRename(t *testing.T) {
|
||||
message: "",
|
||||
expectedHashCmd: []string{"rev-parse", "refs/stash@{4}"},
|
||||
hashResult: "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd\n",
|
||||
expectedDropCmd: []string{"stash", "drop", "stash@{4}"},
|
||||
expectedDropCmd: []string{"stash", "drop", "refs/stash@{4}"},
|
||||
expectedStoreCmd: []string{"stash", "store", "f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -49,9 +49,8 @@ func (self *SubmoduleCommands) GetConfigs(parentModule *models.SubmoduleConfig)
|
||||
|
||||
if len(matches) > 0 {
|
||||
return matches[1], true
|
||||
} else {
|
||||
return "", false
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
configs := []*models.SubmoduleConfig{}
|
||||
|
||||
@@ -57,3 +57,20 @@ func (self *TagCommands) Push(task gocui.Task, remoteName string, tagName string
|
||||
|
||||
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
|
||||
}
|
||||
|
||||
// Return info about an annotated tag in the format:
|
||||
//
|
||||
// Tagger: tagger name <tagger email>
|
||||
// TaggerDate: tagger date
|
||||
//
|
||||
// Tag message
|
||||
//
|
||||
// Should only be called for annotated tags.
|
||||
func (self *TagCommands) ShowAnnotationInfo(tagName string) (string, error) {
|
||||
cmdArgs := NewGitCmd("for-each-ref").
|
||||
Arg("--format=Tagger: %(taggername) %(taggeremail)%0aTaggerDate: %(taggerdate)%0a%0a%(contents)").
|
||||
Arg("refs/tags/" + tagName).
|
||||
ToArgv()
|
||||
|
||||
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package git_commands
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
@@ -26,9 +26,13 @@ func NewTagLoader(
|
||||
}
|
||||
|
||||
func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
||||
// get remote branches, sorted by creation date (descending)
|
||||
// get tags, sorted by creation date (descending)
|
||||
// see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt
|
||||
cmdArgs := NewGitCmd("tag").Arg("--list", "-n", "--sort=-creatordate").ToArgv()
|
||||
cmdArgs := NewGitCmd("for-each-ref").
|
||||
Arg("--sort=-creatordate").
|
||||
Arg("--format=%(refname)%00%(objecttype)%00%(contents:subject)").
|
||||
Arg("refs/tags").
|
||||
ToArgv()
|
||||
tagsOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -36,20 +40,20 @@ func (self *TagLoader) GetTags() ([]*models.Tag, error) {
|
||||
|
||||
split := utils.SplitLines(tagsOutput)
|
||||
|
||||
lineRegex := regexp.MustCompile(`^([^\s]+)(\s+)?(.*)$`)
|
||||
|
||||
tags := lo.Map(split, func(line string, _ int) *models.Tag {
|
||||
matches := lineRegex.FindStringSubmatch(line)
|
||||
tagName := matches[1]
|
||||
message := ""
|
||||
if len(matches) > 3 {
|
||||
message = matches[3]
|
||||
tags := lo.FilterMap(split, func(line string, _ int) (*models.Tag, bool) {
|
||||
fields := strings.SplitN(line, "\x00", 3)
|
||||
if len(fields) != 3 {
|
||||
return nil, false
|
||||
}
|
||||
tagName := fields[0]
|
||||
objectType := fields[1]
|
||||
message := fields[2]
|
||||
|
||||
return &models.Tag{
|
||||
Name: tagName,
|
||||
Message: message,
|
||||
}
|
||||
Name: strings.TrimPrefix(tagName, "refs/tags/"),
|
||||
Message: message,
|
||||
IsAnnotated: objectType == "tag",
|
||||
}, true
|
||||
})
|
||||
|
||||
return tags, nil
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const tagsOutput = `tag1 this is my message
|
||||
tag2
|
||||
tag3 this is my other message
|
||||
`
|
||||
const tagsOutput = "refs/tags/tag1\x00tag\x00this is my message\n" +
|
||||
"refs/tags/tag2\x00commit\x00\n" +
|
||||
"refs/tags/tag3\x00tag\x00this is my other message\n"
|
||||
|
||||
func TestGetTags(t *testing.T) {
|
||||
type scenario struct {
|
||||
@@ -26,18 +25,18 @@ func TestGetTags(t *testing.T) {
|
||||
{
|
||||
testName: "should return no tags if there are none",
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, "", nil),
|
||||
ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, "", nil),
|
||||
expectedTags: []*models.Tag{},
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
testName: "should return tags if present",
|
||||
runner: oscommands.NewFakeRunner(t).
|
||||
ExpectGitArgs([]string{"tag", "--list", "-n", "--sort=-creatordate"}, tagsOutput, nil),
|
||||
ExpectGitArgs([]string{"for-each-ref", "--sort=-creatordate", "--format=%(refname)%00%(objecttype)%00%(contents:subject)", "refs/tags"}, tagsOutput, nil),
|
||||
expectedTags: []*models.Tag{
|
||||
{Name: "tag1", Message: "this is my message"},
|
||||
{Name: "tag2", Message: ""},
|
||||
{Name: "tag3", Message: "this is my other message"},
|
||||
{Name: "tag1", Message: "this is my message", IsAnnotated: true},
|
||||
{Name: "tag2", Message: "", IsAnnotated: false},
|
||||
{Name: "tag3", Message: "this is my other message", IsAnnotated: true},
|
||||
},
|
||||
expectedError: nil,
|
||||
},
|
||||
|
||||
@@ -66,9 +66,8 @@ func (self *WorkingTreeCommands) UnstageAll() error {
|
||||
func (self *WorkingTreeCommands) UnStageFile(paths []string, tracked bool) error {
|
||||
if tracked {
|
||||
return self.UnstageTrackedFiles(paths)
|
||||
} else {
|
||||
return self.UnstageUntrackedFiles(paths)
|
||||
}
|
||||
return self.UnstageUntrackedFiles(paths)
|
||||
}
|
||||
|
||||
func (self *WorkingTreeCommands) UnstageTrackedFiles(paths []string) error {
|
||||
|
||||
@@ -2,6 +2,7 @@ package git_config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
@@ -39,7 +40,8 @@ func runGitConfigCmd(cmd *exec.Cmd) (string, error) {
|
||||
cmd.Stderr = io.Discard
|
||||
|
||||
err := cmd.Run()
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok {
|
||||
if waitStatus.ExitStatus() == 1 {
|
||||
return "", fmt.Errorf("the key is not found for %s", cmd.Args)
|
||||
|
||||
@@ -46,9 +46,8 @@ func (self *HostingServiceMgr) GetPullRequestURL(from string, to string) (string
|
||||
|
||||
if to == "" {
|
||||
return gitService.getPullRequestURLIntoDefaultBranch(url.QueryEscape(from)), nil
|
||||
} else {
|
||||
return gitService.getPullRequestURLIntoTargetBranch(url.QueryEscape(from), url.QueryEscape(to)), nil
|
||||
}
|
||||
return gitService.getPullRequestURLIntoTargetBranch(url.QueryEscape(from), url.QueryEscape(to)), nil
|
||||
}
|
||||
|
||||
func (self *HostingServiceMgr) GetCommitURL(commitHash string) (string, error) {
|
||||
|
||||
@@ -10,7 +10,7 @@ type StashEntry struct {
|
||||
}
|
||||
|
||||
func (s *StashEntry) FullRefName() string {
|
||||
return s.RefName()
|
||||
return "refs/" + s.RefName()
|
||||
}
|
||||
|
||||
func (s *StashEntry) RefName() string {
|
||||
|
||||
@@ -3,9 +3,13 @@ package models
|
||||
// Tag : A git tag
|
||||
type Tag struct {
|
||||
Name string
|
||||
|
||||
// this is either the first line of the message of an annotated tag, or the
|
||||
// first line of a commit message for a lightweight tag
|
||||
Message string
|
||||
|
||||
// true if this is an annotated tag, false if it's a lightweight tag
|
||||
IsAnnotated bool
|
||||
}
|
||||
|
||||
func (t *Tag) FullRefName() string {
|
||||
|
||||
@@ -391,6 +391,7 @@ func (self *cmdObjRunner) getCheckForCredentialRequestFunc() func([]byte) (Crede
|
||||
`Username\s*for\s*'.+':`: Username,
|
||||
`Enter\s*passphrase\s*for\s*key\s*'.+':`: Passphrase,
|
||||
`Enter\s*PIN\s*for\s*.+\s*key\s*.+:`: PIN,
|
||||
`Enter\s*PIN\s*for\s*'.+':`: PIN,
|
||||
`.*2FA Token.*`: Token,
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,17 @@ func TestProcessOutput(t *testing.T) {
|
||||
expectedToWrite: "passphrase",
|
||||
},
|
||||
{
|
||||
name: "pin prompt",
|
||||
name: "security key pin prompt",
|
||||
promptUserForCredential: defaultPromptUserForCredential,
|
||||
output: "Enter PIN for key '123':",
|
||||
expectedToWrite: "pin",
|
||||
},
|
||||
{
|
||||
name: "pkcs11 key pin prompt",
|
||||
promptUserForCredential: defaultPromptUserForCredential,
|
||||
output: "Enter PIN for '123':",
|
||||
expectedToWrite: "pin",
|
||||
},
|
||||
{
|
||||
name: "2FA token prompt",
|
||||
promptUserForCredential: defaultPromptUserForCredential,
|
||||
|
||||
@@ -222,7 +222,7 @@ func (c *OSCommand) PipeCommands(cmdObjs ...*CmdObj) error {
|
||||
|
||||
c.LogCommand(logCmdStr, true)
|
||||
|
||||
for i := 0; i < len(cmds)-1; i++ {
|
||||
for i := range len(cmds) - 1 {
|
||||
stdout, err := cmds[i].StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -283,7 +283,7 @@ func PrepareForChildren(cmd *exec.Cmd) {
|
||||
}
|
||||
|
||||
func (c *OSCommand) CopyToClipboard(str string) error {
|
||||
escaped := strings.Replace(str, "\n", "\\n", -1)
|
||||
escaped := strings.ReplaceAll(str, "\n", "\\n")
|
||||
truncated := utils.TruncateWithEllipsis(escaped, 40)
|
||||
|
||||
msg := utils.ResolvePlaceholderString(
|
||||
|
||||
@@ -72,30 +72,22 @@ func (self *patchPresenter) format() string {
|
||||
|
||||
lineIdx++
|
||||
}
|
||||
appendFormattedLine := func(line string, style style.TextStyle) {
|
||||
formattedLine := self.formatLine(
|
||||
line,
|
||||
style,
|
||||
lineIdx,
|
||||
)
|
||||
|
||||
appendLine(formattedLine)
|
||||
}
|
||||
|
||||
for _, line := range self.patch.header {
|
||||
appendFormattedLine(line, theme.DefaultTextColor.SetBold())
|
||||
// always passing false for 'included' here because header lines are not part of the patch
|
||||
appendLine(self.formatLineAux(line, theme.DefaultTextColor.SetBold(), false))
|
||||
}
|
||||
|
||||
for _, hunk := range self.patch.hunks {
|
||||
appendLine(
|
||||
self.formatLine(
|
||||
self.formatLineAux(
|
||||
hunk.formatHeaderStart(),
|
||||
style.FgCyan,
|
||||
lineIdx,
|
||||
false,
|
||||
) +
|
||||
// we're splitting the line into two parts: the diff header and the context
|
||||
// We explicitly pass 'included' as false here so that we're only tagging the
|
||||
// first half of the line as included if the line is indeed included.
|
||||
// We explicitly pass 'included' as false for both because these are not part
|
||||
// of the actual patch
|
||||
self.formatLineAux(
|
||||
hunk.headerContext,
|
||||
theme.DefaultTextColor,
|
||||
@@ -104,7 +96,12 @@ func (self *patchPresenter) format() string {
|
||||
)
|
||||
|
||||
for _, line := range hunk.bodyLines {
|
||||
appendFormattedLine(line.Content, self.patchLineStyle(line))
|
||||
style := self.patchLineStyle(line)
|
||||
if line.IsChange() {
|
||||
appendLine(self.formatLine(line.Content, style, lineIdx))
|
||||
} else {
|
||||
appendLine(self.formatLineAux(line.Content, style, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ func (self *Patch) HunkStartIdx(hunkIndex int) int {
|
||||
hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1)
|
||||
|
||||
result := len(self.header)
|
||||
for i := 0; i < hunkIndex; i++ {
|
||||
for i := range hunkIndex {
|
||||
result += self.hunks[i].lineCount()
|
||||
}
|
||||
return result
|
||||
@@ -115,15 +115,22 @@ func (self *Patch) HunkContainingLine(idx int) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Returns the patch line index of the next change (i.e. addition or deletion).
|
||||
func (self *Patch) GetNextChangeIdx(idx int) int {
|
||||
// Returns the patch line index of the next change (i.e. addition or deletion)
|
||||
// that matches the same "included" state, given the includedLines. If you don't
|
||||
// care about included states, pass nil for includedLines and false for included.
|
||||
func (self *Patch) GetNextChangeIdxOfSameIncludedState(idx int, includedLines []int, included bool) (int, bool) {
|
||||
idx = lo.Clamp(idx, 0, self.LineCount()-1)
|
||||
|
||||
lines := self.Lines()
|
||||
|
||||
isMatch := func(i int, line *PatchLine) bool {
|
||||
sameIncludedState := lo.Contains(includedLines, i) == included
|
||||
return line.IsChange() && sameIncludedState
|
||||
}
|
||||
|
||||
for i, line := range lines[idx:] {
|
||||
if line.isChange() {
|
||||
return i + idx
|
||||
if isMatch(i+idx, line) {
|
||||
return i + idx, true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,13 +138,18 @@ func (self *Patch) GetNextChangeIdx(idx int) int {
|
||||
// return the index of the last change
|
||||
for i := len(lines) - 1; i >= 0; i-- {
|
||||
line := lines[i]
|
||||
if line.isChange() {
|
||||
return i
|
||||
if isMatch(i, line) {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
|
||||
// should not be possible
|
||||
return 0
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Returns the patch line index of the next change (i.e. addition or deletion).
|
||||
func (self *Patch) GetNextChangeIdx(idx int) int {
|
||||
result, _ := self.GetNextChangeIdxOfSameIncludedState(idx, nil, false)
|
||||
return result
|
||||
}
|
||||
|
||||
// Returns the length of the patch in lines
|
||||
|
||||
@@ -91,7 +91,7 @@ func (p *PatchBuilder) addFileWhole(info *fileInfo) {
|
||||
// add every line index
|
||||
// TODO: add tests and then use lo.Range to simplify
|
||||
info.includedLineIndices = make([]int, lineCount)
|
||||
for i := 0; i < lineCount; i++ {
|
||||
for i := range lineCount {
|
||||
info.includedLineIndices[i] = i
|
||||
}
|
||||
}
|
||||
@@ -124,14 +124,6 @@ func (p *PatchBuilder) RemoveFile(filename string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIndicesForRange(first, last int) []int {
|
||||
indices := []int{}
|
||||
for i := first; i <= last; i++ {
|
||||
indices = append(indices, i)
|
||||
}
|
||||
return indices
|
||||
}
|
||||
|
||||
func (p *PatchBuilder) getFileInfo(filename string) (*fileInfo, error) {
|
||||
info, ok := p.fileInfoMap[filename]
|
||||
if ok {
|
||||
@@ -152,24 +144,24 @@ func (p *PatchBuilder) getFileInfo(filename string) (*fileInfo, error) {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (p *PatchBuilder) AddFileLineRange(filename string, firstLineIdx, lastLineIdx int) error {
|
||||
func (p *PatchBuilder) AddFileLineRange(filename string, lineIndices []int) error {
|
||||
info, err := p.getFileInfo(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.mode = PART
|
||||
info.includedLineIndices = lo.Union(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx))
|
||||
info.includedLineIndices = lo.Union(info.includedLineIndices, lineIndices)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PatchBuilder) RemoveFileLineRange(filename string, firstLineIdx, lastLineIdx int) error {
|
||||
func (p *PatchBuilder) RemoveFileLineRange(filename string, lineIndices []int) error {
|
||||
info, err := p.getFileInfo(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.mode = PART
|
||||
info.includedLineIndices, _ = lo.Difference(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx))
|
||||
info.includedLineIndices, _ = lo.Difference(info.includedLineIndices, lineIndices)
|
||||
if len(info.includedLineIndices) == 0 {
|
||||
p.removeFile(info)
|
||||
}
|
||||
@@ -211,9 +203,8 @@ func (p *PatchBuilder) RenderPatchForFile(opts RenderPatchForFileOpts) string {
|
||||
|
||||
if opts.Plain {
|
||||
return patch.FormatPlain()
|
||||
} else {
|
||||
return patch.FormatView(FormatViewOpts{})
|
||||
}
|
||||
return patch.FormatView(FormatViewOpts{})
|
||||
}
|
||||
|
||||
func (p *PatchBuilder) renderEachFilePatch(plain bool) []string {
|
||||
@@ -287,11 +278,5 @@ func (p *PatchBuilder) NewPatchRequired(from string, to string, reverse bool) bo
|
||||
}
|
||||
|
||||
func (p *PatchBuilder) AllFilesInPatch() []string {
|
||||
files := make([]string, 0, len(p.fileInfoMap))
|
||||
|
||||
for filename := range p.fileInfoMap {
|
||||
files = append(files, filename)
|
||||
}
|
||||
|
||||
return files
|
||||
return lo.Keys(p.fileInfoMap)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type PatchLine struct {
|
||||
Content string // something like '+ hello' (note the first character is not removed)
|
||||
}
|
||||
|
||||
func (self *PatchLine) isChange() bool {
|
||||
func (self *PatchLine) IsChange() bool {
|
||||
return self.Kind == ADDITION || self.Kind == DELETION
|
||||
}
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@ func (self *patchTransformer) transformHeader() []string {
|
||||
result = append(result, line)
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
return self.patch.header
|
||||
}
|
||||
|
||||
return self.patch.header
|
||||
}
|
||||
|
||||
func (self *patchTransformer) transformHunks() []*Hunk {
|
||||
|
||||
@@ -288,7 +288,7 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([]
|
||||
for _, pathToReplace := range pathsToReplace {
|
||||
err, didReplace := yaml_utils.RenameYamlKey(&rootNode, pathToReplace.oldPath, pathToReplace.newName)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s` for key %s: %s", path, strings.Join(pathToReplace.oldPath, "."), err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s` for key %s: %w", path, strings.Join(pathToReplace.oldPath, "."), err)
|
||||
}
|
||||
if didReplace {
|
||||
changes.Add(fmt.Sprintf("Renamed '%s' to '%s'", strings.Join(pathToReplace.oldPath, "."), pathToReplace.newName))
|
||||
@@ -297,27 +297,27 @@ func computeMigratedConfig(path string, content []byte, changes *ChangesSet) ([]
|
||||
|
||||
err = changeNullKeybindingsToDisabled(&rootNode, changes)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err)
|
||||
}
|
||||
|
||||
err = changeElementToSequence(&rootNode, []string{"git", "commitPrefix"}, changes)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err)
|
||||
}
|
||||
|
||||
err = changeCommitPrefixesMap(&rootNode, changes)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err)
|
||||
}
|
||||
|
||||
err = changeCustomCommandStreamAndOutputToOutputEnum(&rootNode, changes)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err)
|
||||
}
|
||||
|
||||
err = migrateAllBranchesLogCmd(&rootNode, changes)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %s", path, err)
|
||||
return nil, false, fmt.Errorf("Couldn't migrate config file at `%s`: %w", path, err)
|
||||
}
|
||||
|
||||
// Add more migrations here...
|
||||
|
||||
@@ -384,6 +384,9 @@ gui:
|
||||
# When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
|
||||
mouseEvents: true
|
||||
|
||||
# If true, do not show a warning when amending a commit.
|
||||
skipAmendWarning: false
|
||||
|
||||
# If true, do not show a warning when discarding changes in the staging view.
|
||||
skipDiscardChangeWarning: false
|
||||
|
||||
@@ -557,7 +560,7 @@ gui:
|
||||
screenMode: normal
|
||||
|
||||
# Window border style.
|
||||
# One of 'rounded' (default) | 'single' | 'double' | 'hidden'
|
||||
# One of 'rounded' (default) | 'single' | 'double' | 'hidden' | 'bold'
|
||||
border: rounded
|
||||
|
||||
# If true, show a seriously epic explosion animation when nuking the working tree.
|
||||
|
||||
@@ -74,6 +74,8 @@ type GuiConfig struct {
|
||||
// If true, capture mouse events.
|
||||
// When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
|
||||
MouseEvents bool `yaml:"mouseEvents"`
|
||||
// If true, do not show a warning when amending a commit.
|
||||
SkipAmendWarning bool `yaml:"skipAmendWarning"`
|
||||
// If true, do not show a warning when discarding changes in the staging view.
|
||||
SkipDiscardChangeWarning bool `yaml:"skipDiscardChangeWarning"`
|
||||
// If true, do not show warning when applying/popping the stash
|
||||
@@ -105,6 +107,8 @@ type GuiConfig struct {
|
||||
// makes it much easier to work with diffs that have long lines, e.g.
|
||||
// paragraphs of markdown text.
|
||||
WrapLinesInStagingView bool `yaml:"wrapLinesInStagingView"`
|
||||
// If true, hunk selection mode will be enabled by default when entering the staging view.
|
||||
UseHunkModeInStagingView bool `yaml:"useHunkModeInStagingView"`
|
||||
// One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
|
||||
Language string `yaml:"language" jsonschema:"enum=auto,enum=en,enum=zh-TW,enum=zh-CN,enum=pl,enum=nl,enum=ja,enum=ko,enum=ru"`
|
||||
// Format used when displaying time e.g. commit time.
|
||||
@@ -164,8 +168,8 @@ type GuiConfig struct {
|
||||
// One of: 'normal' (default) | 'half' | 'full'
|
||||
ScreenMode string `yaml:"screenMode" jsonschema:"enum=normal,enum=half,enum=full"`
|
||||
// Window border style.
|
||||
// One of 'rounded' (default) | 'single' | 'double' | 'hidden'
|
||||
Border string `yaml:"border" jsonschema:"enum=single,enum=double,enum=rounded,enum=hidden"`
|
||||
// One of 'rounded' (default) | 'single' | 'double' | 'hidden' | 'bold'
|
||||
Border string `yaml:"border" jsonschema:"enum=single,enum=double,enum=rounded,enum=hidden,enum=bold"`
|
||||
// If true, show a seriously epic explosion animation when nuking the working tree.
|
||||
AnimateExplosion bool `yaml:"animateExplosion"`
|
||||
// Whether to stack UI components on top of each other.
|
||||
@@ -734,6 +738,7 @@ func GetDefaultConfig() *UserConfig {
|
||||
ScrollOffBehavior: "margin",
|
||||
TabWidth: 4,
|
||||
MouseEvents: true,
|
||||
SkipAmendWarning: false,
|
||||
SkipDiscardChangeWarning: false,
|
||||
SkipStashWarning: false,
|
||||
SidePanelWidth: 0.3333,
|
||||
@@ -742,6 +747,7 @@ func GetDefaultConfig() *UserConfig {
|
||||
MainPanelSplitMode: "flexible",
|
||||
EnlargedSideViewLocation: "left",
|
||||
WrapLinesInStagingView: true,
|
||||
UseHunkModeInStagingView: false,
|
||||
Language: "auto",
|
||||
TimeFormat: "02 Jan 06",
|
||||
ShortTimeFormat: time.Kitchen,
|
||||
|
||||
@@ -56,7 +56,7 @@ func validateKeybindingsRecurse(path string, node any) error {
|
||||
}
|
||||
}
|
||||
} else if value.Kind() == reflect.Slice {
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
for i := range value.Len() {
|
||||
if err := validateKeybindingsRecurse(
|
||||
fmt.Sprintf("%s[%d]", path, i), value.Index(i).Interface()); err != nil {
|
||||
return err
|
||||
|
||||
@@ -93,7 +93,8 @@ func (self *BackgroundRoutineMgr) startBackgroundFilesRefresh(refreshInterval in
|
||||
self.gui.waitForIntro.Wait()
|
||||
|
||||
self.goEvery(time.Second*time.Duration(refreshInterval), self.gui.stopChan, func() error {
|
||||
return self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ func (self *BackgroundRoutineMgr) goEvery(interval time.Duration, stop chan stru
|
||||
func (self *BackgroundRoutineMgr) backgroundFetch() (err error) {
|
||||
err = self.gui.git.Sync.FetchBackground()
|
||||
|
||||
_ = self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.SYNC})
|
||||
self.gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.SYNC})
|
||||
|
||||
if err == nil {
|
||||
err = self.gui.helpers.BranchesHelper.AutoForwardBranches()
|
||||
|
||||
@@ -48,7 +48,7 @@ func (gui *Gui) LogCommand(cmdStr string, commandLine bool) {
|
||||
textStyle = style.FgMagenta
|
||||
}
|
||||
gui.GuiLog = append(gui.GuiLog, cmdStr)
|
||||
indentedCmdStr := " " + strings.Replace(cmdStr, "\n", "\n ", -1)
|
||||
indentedCmdStr := " " + strings.ReplaceAll(cmdStr, "\n", "\n ")
|
||||
fmt.Fprint(gui.Views.Extras, "\n"+textStyle.Sprint(indentedCmdStr))
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,13 @@ type FilteredList[T any] struct {
|
||||
getFilterFields func(T) []string
|
||||
filter string
|
||||
|
||||
mutex *deadlock.Mutex
|
||||
mutex deadlock.Mutex
|
||||
}
|
||||
|
||||
func NewFilteredList[T any](getList func() []T, getFilterFields func(T) []string) *FilteredList[T] {
|
||||
return &FilteredList[T]{
|
||||
getList: getList,
|
||||
getFilterFields: getFilterFields,
|
||||
mutex: &deadlock.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -257,11 +257,11 @@ func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) {
|
||||
// Need to render first so that it knows the non-model items
|
||||
self.renderLines(-1, -1)
|
||||
|
||||
for i := 0; i < len(s.modelIndices); i++ {
|
||||
for i := range len(s.modelIndices) {
|
||||
assert.Equal(t, s.expectedViewIndices[i], self.ModelIndexToViewIndex(s.modelIndices[i]))
|
||||
}
|
||||
|
||||
for i := 0; i < len(s.viewIndices); i++ {
|
||||
for i := range len(s.viewIndices) {
|
||||
assert.Equal(t, s.expectedModelIndices[i], self.ViewIndexToModelIndex(s.viewIndices[i]))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -144,7 +144,7 @@ func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
|
||||
}
|
||||
|
||||
menuItems := self.FilteredListViewModel.GetItems()
|
||||
var prevSection *types.MenuSection = nil
|
||||
var prevSection *types.MenuSection
|
||||
for i, menuItem := range menuItems {
|
||||
if menuItem.Section != nil && menuItem.Section != prevSection {
|
||||
if prevSection != nil {
|
||||
|
||||
@@ -12,7 +12,7 @@ type MergeConflictsContext struct {
|
||||
types.Context
|
||||
viewModel *ConflictsViewModel
|
||||
c *ContextCommon
|
||||
mutex *deadlock.Mutex
|
||||
mutex deadlock.Mutex
|
||||
}
|
||||
|
||||
type ConflictsViewModel struct {
|
||||
@@ -33,7 +33,6 @@ func NewMergeConflictsContext(
|
||||
|
||||
return &MergeConflictsContext{
|
||||
viewModel: viewModel,
|
||||
mutex: &deadlock.Mutex{},
|
||||
Context: NewSimpleContext(
|
||||
NewBaseContext(NewBaseContextOpts{
|
||||
Kind: types.MAIN_CONTEXT,
|
||||
@@ -57,7 +56,7 @@ func (self *MergeConflictsContext) SetState(state *mergeconflicts.State) {
|
||||
}
|
||||
|
||||
func (self *MergeConflictsContext) GetMutex() *deadlock.Mutex {
|
||||
return self.mutex
|
||||
return &self.mutex
|
||||
}
|
||||
|
||||
func (self *MergeConflictsContext) SetUserScrolling(isScrolling bool) {
|
||||
|
||||
@@ -15,7 +15,7 @@ type PatchExplorerContext struct {
|
||||
viewTrait *ViewTrait
|
||||
getIncludedLineIndices func() []int
|
||||
c *ContextCommon
|
||||
mutex *deadlock.Mutex
|
||||
mutex deadlock.Mutex
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -36,7 +36,6 @@ func NewPatchExplorerContext(
|
||||
state: nil,
|
||||
viewTrait: NewViewTrait(view),
|
||||
c: c,
|
||||
mutex: &deadlock.Mutex{},
|
||||
getIncludedLineIndices: getIncludedLineIndices,
|
||||
SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||
View: view,
|
||||
@@ -137,7 +136,7 @@ func (self *PatchExplorerContext) NavigateTo(selectedLineIdx int) {
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) GetMutex() *deadlock.Mutex {
|
||||
return self.mutex
|
||||
return &self.mutex
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
|
||||
|
||||
@@ -79,9 +79,8 @@ func (self *SuggestionsContext) RefreshSuggestions() {
|
||||
if findSuggestionsFn != nil {
|
||||
suggestions := findSuggestionsFn(self.c.GetPromptInput())
|
||||
return func() { self.SetSuggestions(suggestions) }
|
||||
} else {
|
||||
return func() {}
|
||||
}
|
||||
return func() {}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -77,9 +77,8 @@ func (self *ListCursor) SetSelectionRangeAndMode(selectedIdx, rangeStartIdx int,
|
||||
func (self *ListCursor) GetSelectionRangeAndMode() (int, int, RangeSelectMode) {
|
||||
if self.IsSelectingRange() {
|
||||
return self.selectedIdx, self.rangeStartIdx, self.rangeSelectMode
|
||||
} else {
|
||||
return self.selectedIdx, self.selectedIdx, self.rangeSelectMode
|
||||
}
|
||||
return self.selectedIdx, self.selectedIdx, self.rangeSelectMode
|
||||
}
|
||||
|
||||
func (self *ListCursor) clampValue(value int) int {
|
||||
@@ -134,10 +133,19 @@ func (self *ListCursor) GetRangeStartIdx() (int, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Cancel range select mode, but keep the "moving end" of the range selected.
|
||||
// Used when pressing 'v' or escape to toggle range select mode, for example.
|
||||
func (self *ListCursor) CancelRangeSelect() {
|
||||
self.rangeSelectMode = RangeSelectModeNone
|
||||
}
|
||||
|
||||
// Cancel range select mode, but keep the top of the range selected. Note that
|
||||
// this is different from CancelRangeSelect. Useful after deleting a range of items.
|
||||
func (self *ListCursor) CollapseRangeSelectionToTop() {
|
||||
start, _ := self.GetSelectionRange()
|
||||
self.SetSelection(start)
|
||||
}
|
||||
|
||||
// Returns true if we are in range select mode. Note that we may be in range select
|
||||
// mode and still only selecting a single item. See AreMultipleItemsSelected below.
|
||||
func (self *ListCursor) IsSelectingRange() bool {
|
||||
|
||||
@@ -24,7 +24,7 @@ func OnFocusWrapper(f func() error) func(opts types.OnFocusOpts) error {
|
||||
func (gui *Gui) defaultSideContext() types.Context {
|
||||
if gui.State.Modes.Filtering.Active() {
|
||||
return gui.State.Contexts.LocalCommits
|
||||
} else {
|
||||
return gui.State.Contexts.Files
|
||||
}
|
||||
|
||||
return gui.State.Contexts.Files
|
||||
}
|
||||
|
||||
@@ -54,9 +54,8 @@ func (self *BisectController) openMenu(commit *models.Commit) error {
|
||||
info := self.c.Git().Bisect.GetInfo()
|
||||
if info.Started() {
|
||||
return self.openMidBisectMenu(info, commit)
|
||||
} else {
|
||||
return self.openStartBisectMenu(info, commit)
|
||||
}
|
||||
return self.openStartBisectMenu(info, commit)
|
||||
}
|
||||
|
||||
func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error {
|
||||
@@ -176,7 +175,8 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'b',
|
||||
@@ -193,7 +193,8 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
return nil
|
||||
},
|
||||
DisabledReason: self.require(self.singleItemSelected())(),
|
||||
Key: 'g',
|
||||
@@ -212,7 +213,8 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo,
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
return nil
|
||||
@@ -246,7 +248,8 @@ func (self *BisectController) showBisectCompleteMessage(candidateHashes []string
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -271,20 +274,21 @@ func (self *BisectController) afterMark(selectCurrent bool, waitToReselect bool)
|
||||
}
|
||||
|
||||
func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToReselect bool) error {
|
||||
selectFn := func() error {
|
||||
selectFn := func() {
|
||||
if selectCurrent {
|
||||
self.selectCurrentBisectCommit()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if waitToReselect {
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{}, Then: selectFn})
|
||||
} else {
|
||||
_ = selectFn()
|
||||
|
||||
return self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{}, Then: selectFn})
|
||||
return nil
|
||||
}
|
||||
|
||||
selectFn()
|
||||
|
||||
self.c.Helpers().Bisect.PostBisectCommandRefresh()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BisectController) selectCurrentBisectCommit() {
|
||||
|
||||
@@ -263,15 +263,13 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
||||
if err := self.c.Git().Branch.UnsetUpstream(selectedBranch.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC,
|
||||
Scope: []types.RefreshableView{
|
||||
types.BRANCHES,
|
||||
types.COMMITS,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
return nil
|
||||
},
|
||||
Key: 'u',
|
||||
@@ -289,15 +287,13 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
||||
if err := self.c.Git().Branch.SetUpstream(upstreamRemote, upstreamBranch, selectedBranch.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC,
|
||||
Scope: []types.RefreshableView{
|
||||
types.BRANCHES,
|
||||
types.COMMITS,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
@@ -478,7 +474,8 @@ func (self *BranchesController) forceCheckout() error {
|
||||
if err := self.c.Git().Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -526,7 +523,8 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
|
||||
}
|
||||
|
||||
self.context().SetSelection(0)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BranchesController) localDelete(branches []*models.Branch) error {
|
||||
@@ -537,7 +535,7 @@ func (self *BranchesController) remoteDelete(branches []*models.Branch) error {
|
||||
remoteBranches := lo.Map(branches, func(branch *models.Branch, _ int) *models.RemoteBranch {
|
||||
return &models.RemoteBranch{Name: branch.UpstreamBranch, RemoteName: branch.UpstreamRemote}
|
||||
})
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(remoteBranches)
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(remoteBranches, false)
|
||||
}
|
||||
|
||||
func (self *BranchesController) localAndRemoteDelete(branches []*models.Branch) error {
|
||||
@@ -655,17 +653,17 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
|
||||
WorktreePath: worktreePath,
|
||||
},
|
||||
)
|
||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return err
|
||||
} else {
|
||||
self.c.LogAction(action)
|
||||
|
||||
err := self.c.Git().Sync.FastForward(
|
||||
task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch,
|
||||
)
|
||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.LogAction(action)
|
||||
|
||||
err := self.c.Git().Sync.FastForward(
|
||||
task, branch.Name, branch.UpstreamRemote, branch.UpstreamBranch,
|
||||
)
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -679,7 +677,8 @@ func (self *BranchesController) createSortMenu() error {
|
||||
self.c.GetAppState().LocalBranchSortOrder = sortOrder
|
||||
self.c.SaveAppStateAndLogError()
|
||||
self.c.Contexts().Branches.SetSelection(0)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -702,7 +701,7 @@ func (self *BranchesController) rename(branch *models.Branch) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
_ = self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC,
|
||||
Scope: []types.RefreshableView{types.BRANCHES, types.WORKTREES},
|
||||
})
|
||||
|
||||
@@ -153,7 +153,7 @@ func (self *CommitMessageController) handleCommitIndexChange(value int) error {
|
||||
func (self *CommitMessageController) setCommitMessageAtIndex(index int) (bool, error) {
|
||||
commitMessage, err := self.c.Git().Commit.GetCommitMessageFromHistory(index)
|
||||
if err != nil {
|
||||
if err == git_commands.ErrInvalidCommitIndex {
|
||||
if errors.Is(err, git_commands.ErrInvalidCommitIndex) {
|
||||
return false, nil
|
||||
}
|
||||
return false, errors.New(self.c.Tr.CommitWithoutMessageErr)
|
||||
|
||||
@@ -289,7 +289,8 @@ func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileNode) error {
|
||||
@@ -313,19 +314,13 @@ func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileN
|
||||
// Reset the current patch if there is one.
|
||||
if self.c.Git().Patch.PatchBuilder.Active() {
|
||||
self.c.Git().Patch.PatchBuilder.Reset()
|
||||
if err := self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, node := range selectedNodes {
|
||||
err := node.ForEachFile(func(file *models.CommitFile) error {
|
||||
_ = node.ForEachFile(func(file *models.CommitFile) error {
|
||||
filePaths = append(filePaths, file.GetPath())
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := self.c.Git().Rebase.DiscardOldFileChanges(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), filePaths)
|
||||
@@ -336,7 +331,8 @@ func (self *CommitFilesController) discard(selectedNodes []*filetree.CommitFileN
|
||||
if self.context().RangeSelectEnabled() {
|
||||
self.context().GetList().CancelRangeSelect()
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -103,13 +103,13 @@ func (self *ContextLinesController) applyChange() error {
|
||||
switch currentContext.GetKey() {
|
||||
// we make an exception for our staging and patch building contexts because they actually need to refresh their state afterwards.
|
||||
case context.PATCH_BUILDING_MAIN_CONTEXT_KEY:
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.PATCH_BUILDING}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.PATCH_BUILDING}})
|
||||
case context.STAGING_MAIN_CONTEXT_KEY, context.STAGING_SECONDARY_CONTEXT_KEY:
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STAGING}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STAGING}})
|
||||
default:
|
||||
currentContext.HandleRenderToMain()
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ContextLinesController) checkCanChangeContext() error {
|
||||
|
||||
@@ -4,10 +4,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/generics/set"
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type CustomPatchOptionsMenuAction struct {
|
||||
@@ -189,9 +192,9 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error
|
||||
})
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return pull(false)
|
||||
}
|
||||
|
||||
return pull(false)
|
||||
}
|
||||
|
||||
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
|
||||
@@ -267,15 +270,42 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommitBefore() e
|
||||
func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error {
|
||||
self.returnFocusFromPatchExplorerIfNecessary()
|
||||
|
||||
action := self.c.Tr.Actions.ApplyPatch
|
||||
if reverse {
|
||||
action = "Apply patch in reverse"
|
||||
affectedUnstagedFiles := self.getAffectedUnstagedFiles()
|
||||
|
||||
apply := func() error {
|
||||
action := self.c.Tr.Actions.ApplyPatch
|
||||
if reverse {
|
||||
action = "Apply patch in reverse"
|
||||
}
|
||||
self.c.LogAction(action)
|
||||
|
||||
if len(affectedUnstagedFiles) > 0 {
|
||||
if err := self.c.Git().WorkingTree.StageFiles(affectedUnstagedFiles, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := self.c.Git().Patch.ApplyCustomPatch(reverse, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
self.c.LogAction(action)
|
||||
if err := self.c.Git().Patch.ApplyCustomPatch(reverse, true); err != nil {
|
||||
return err
|
||||
|
||||
if len(affectedUnstagedFiles) > 0 {
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.MustStageFilesAffectedByPatchTitle,
|
||||
Prompt: self.c.Tr.MustStageFilesAffectedByPatchWarning,
|
||||
HandleConfirm: func() error {
|
||||
return apply()
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
|
||||
return apply()
|
||||
}
|
||||
|
||||
func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
|
||||
@@ -290,3 +320,17 @@ func (self *CustomPatchOptionsMenuAction) copyPatchToClipboard() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a list of files that have unstaged changes and are contained in the patch.
|
||||
func (self *CustomPatchOptionsMenuAction) getAffectedUnstagedFiles() []string {
|
||||
unstagedFiles := set.NewFromSlice(lo.FilterMap(self.c.Model().Files, func(f *models.File, _ int) (string, bool) {
|
||||
if f.GetHasUnstagedChanges() {
|
||||
return f.GetPath(), true
|
||||
}
|
||||
return "", false
|
||||
}))
|
||||
|
||||
return lo.Filter(self.c.Git().Patch.PatchBuilder.AllFilesInPatch(), func(patchFile string, _ int) bool {
|
||||
return unstagedFiles.Includes(patchFile)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ func (self *DiffingMenuAction) Call() error {
|
||||
OnPress: func() error {
|
||||
self.c.Modes().Diffing.Ref = name
|
||||
// can scope this down based on current view but too lazy right now
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}...)
|
||||
@@ -38,7 +39,8 @@ func (self *DiffingMenuAction) Call() error {
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRefsSuggestionsFunc(),
|
||||
HandleConfirm: func(response string) error {
|
||||
self.c.Modes().Diffing.Ref = strings.TrimSpace(response)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -53,14 +55,16 @@ func (self *DiffingMenuAction) Call() error {
|
||||
Label: self.c.Tr.SwapDiff,
|
||||
OnPress: func() error {
|
||||
self.c.Modes().Diffing.Reverse = !self.c.Modes().Diffing.Reverse
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.ExitDiffMode,
|
||||
OnPress: func() error {
|
||||
self.c.Modes().Diffing = diffing.New()
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}...)
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
type FilesController struct {
|
||||
baseController // nolint: unused
|
||||
baseController
|
||||
*ListControllerTrait[*filetree.FileNode]
|
||||
c *ControllerCommon
|
||||
}
|
||||
@@ -262,15 +262,14 @@ func (self *FilesController) GetOnRenderToMain() func() {
|
||||
}
|
||||
if node.File.ShortStatus == "DU" || node.File.ShortStatus == "UD" {
|
||||
cmdObj := self.c.Git().Diff.DiffCmdObj([]string{"--base", "--", node.GetPath()})
|
||||
task := types.NewRunPtyTask(cmdObj.GetCmd())
|
||||
task.Prefix = message + "\n\n"
|
||||
prefix := message + "\n\n"
|
||||
if node.File.ShortStatus == "DU" {
|
||||
task.Prefix += self.c.Tr.MergeConflictIncomingDiff
|
||||
prefix += self.c.Tr.MergeConflictIncomingDiff
|
||||
} else {
|
||||
task.Prefix += self.c.Tr.MergeConflictCurrentDiff
|
||||
prefix += self.c.Tr.MergeConflictCurrentDiff
|
||||
}
|
||||
task.Prefix += "\n\n"
|
||||
opts.Main.Task = task
|
||||
prefix += "\n\n"
|
||||
opts.Main.Task = types.NewRunPtyTaskWithPrefix(cmdObj.GetCmd(), prefix)
|
||||
} else {
|
||||
opts.Main.Task = types.NewRenderStringTask(message)
|
||||
}
|
||||
@@ -486,9 +485,7 @@ func (self *FilesController) press(nodes []*filetree.FileNode) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC})
|
||||
|
||||
self.context().HandleFocus(types.OnFocusOpts{})
|
||||
return nil
|
||||
@@ -566,7 +563,8 @@ func (self *FilesController) handleNonInlineConflict(file *models.File) error {
|
||||
if err := command(file.GetPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
return nil
|
||||
}
|
||||
keepItem := &types.MenuItem{
|
||||
Label: self.c.Tr.MergeConflictKeepFile,
|
||||
@@ -611,9 +609,7 @@ func (self *FilesController) toggleStagedAll() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC})
|
||||
|
||||
self.context().HandleFocus(types.OnFocusOpts{})
|
||||
return nil
|
||||
@@ -683,7 +679,8 @@ func (self *FilesController) ignoreOrExcludeTracked(node *filetree.FileNode, trA
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeUntracked(node *filetree.FileNode, trAction string, f func(string) error) error {
|
||||
@@ -693,7 +690,8 @@ func (self *FilesController) ignoreOrExcludeUntracked(node *filetree.FileNode, t
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeFile(node *filetree.FileNode, trText string, trPrompt string, trAction string, f func(string) error) error {
|
||||
@@ -755,7 +753,8 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
|
||||
}
|
||||
|
||||
func (self *FilesController) refresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) handleAmendCommitPress() error {
|
||||
@@ -795,7 +794,7 @@ func (self *FilesController) handleAmendCommitPress() error {
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
} else if !self.c.UserConfig().Gui.SkipAmendWarning {
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.AmendLastCommitTitle,
|
||||
Prompt: self.c.Tr.SureToAmend,
|
||||
@@ -803,9 +802,11 @@ func (self *FilesController) handleAmendCommitPress() error {
|
||||
return doAmend()
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return doAmend()
|
||||
}
|
||||
|
||||
func (self *FilesController) isResolvingConflicts() bool {
|
||||
@@ -898,12 +899,11 @@ func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayF
|
||||
// Whenever we switch between untracked and other filters, we need to refresh the files view
|
||||
// because the untracked files filter applies when running `git status`.
|
||||
if previousFilter != filter && (previousFilter == filetree.DisplayUntracked || filter == filetree.DisplayUntracked) {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}, Mode: types.ASYNC})
|
||||
} else {
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) edit(nodes []*filetree.FileNode) error {
|
||||
@@ -1176,7 +1176,8 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro
|
||||
if err := stashFunc(stashComment); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1196,7 +1197,7 @@ func (self *FilesController) fetch() error {
|
||||
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.SYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.SYNC})
|
||||
|
||||
if err == nil {
|
||||
err = self.c.Helpers().BranchesHelper.AutoForwardBranches()
|
||||
@@ -1321,7 +1322,8 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error {
|
||||
}
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}})
|
||||
return nil
|
||||
},
|
||||
Key: self.c.KeybindingsOpts().GetKey(self.c.UserConfig().Keybinding.Files.ConfirmDiscard),
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
@@ -1347,7 +1349,8 @@ func (self *FilesController) remove(selectedNodes []*filetree.FileNode) error {
|
||||
}
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.WORKTREES}})
|
||||
return nil
|
||||
},
|
||||
Key: 'u',
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
@@ -1388,7 +1391,8 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -122,9 +122,10 @@ func (self *FilteringMenuAction) setFiltering() error {
|
||||
|
||||
self.c.Context().Push(self.c.Contexts().LocalCommits, types.OnFocusOpts{})
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() error {
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() {
|
||||
self.c.Contexts().LocalCommits.SetSelection(0)
|
||||
self.c.Contexts().LocalCommits.FocusLine()
|
||||
return nil
|
||||
}})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -143,7 +143,8 @@ func (self *GlobalController) createCustomPatchOptionsMenu() error {
|
||||
}
|
||||
|
||||
func (self *GlobalController) refresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *GlobalController) nextScreenMode() error {
|
||||
|
||||
@@ -22,13 +22,14 @@ func (self *BisectHelper) Reset() error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.PostBisectCommandRefresh()
|
||||
self.PostBisectCommandRefresh()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BisectHelper) PostBisectCommandRefresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{}})
|
||||
func (self *BisectHelper) PostBisectCommandRefresh() {
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{}})
|
||||
}
|
||||
|
||||
@@ -47,9 +47,10 @@ func (self *BranchesHelper) ConfirmLocalDelete(branches []*models.Branch) error
|
||||
if err := self.c.Git().Branch.LocalDelete(branchNames, true); err != nil {
|
||||
return err
|
||||
}
|
||||
selectionStart, _ := self.c.Contexts().Branches.GetSelectionRange()
|
||||
self.c.Contexts().Branches.SetSelectedLineIdx(selectionStart)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
|
||||
self.c.Contexts().Branches.CollapseRangeSelectionToTop()
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ func (self *BranchesHelper) ConfirmLocalDelete(branches []*models.Branch) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) ConfirmDeleteRemote(remoteBranches []*models.RemoteBranch) error {
|
||||
func (self *BranchesHelper) ConfirmDeleteRemote(remoteBranches []*models.RemoteBranch, resetRemoteBranchesSelection bool) error {
|
||||
var title string
|
||||
if len(remoteBranches) == 1 {
|
||||
title = utils.ResolvePlaceholderString(
|
||||
@@ -113,7 +114,11 @@ func (self *BranchesHelper) ConfirmDeleteRemote(remoteBranches []*models.RemoteB
|
||||
if err := self.deleteRemoteBranches(remoteBranches, task); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
if resetRemoteBranchesSelection {
|
||||
self.c.Contexts().RemoteBranches.CollapseRangeSelectionToTop()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -178,10 +183,9 @@ func (self *BranchesHelper) ConfirmLocalAndRemoteDelete(branches []*models.Branc
|
||||
return err
|
||||
}
|
||||
|
||||
selectionStart, _ := self.c.Contexts().Branches.GetSelectionRange()
|
||||
self.c.Contexts().Branches.SetSelectedLineIdx(selectionStart)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
self.c.Contexts().Branches.CollapseRangeSelectionToTop()
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -295,7 +299,7 @@ func (self *BranchesHelper) AutoForwardBranches() error {
|
||||
self.c.LogCommand(strings.TrimRight(updateCommands, "\n"), false)
|
||||
err := self.c.Git().Branch.UpdateBranchRefs(updateCommands)
|
||||
|
||||
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES}, Mode: types.SYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES}, Mode: types.SYNC})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package helpers
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
@@ -77,14 +76,34 @@ func (self *CherryPickHelper) Paste() error {
|
||||
"numCommits": strconv.Itoa(len(self.getData().CherryPickedCommits)),
|
||||
}),
|
||||
HandleConfirm: func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.CherryPickingStatus, func(gocui.Task) error {
|
||||
return self.c.WithWaitingStatusSync(self.c.Tr.CherryPickingStatus, func() error {
|
||||
mustStash := IsWorkingTreeDirty(self.c.Model().Files)
|
||||
|
||||
self.c.LogAction(self.c.Tr.Actions.CherryPick)
|
||||
result := self.c.Git().Rebase.CherryPickCommits(self.getData().CherryPickedCommits)
|
||||
err := self.rebaseHelper.CheckMergeOrRebase(result)
|
||||
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.AutoStashForCherryPicking); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cherryPickedCommits := self.getData().CherryPickedCommits
|
||||
result := self.c.Git().Rebase.CherryPickCommits(cherryPickedCommits)
|
||||
err := self.rebaseHelper.CheckMergeOrRebaseWithRefreshOptions(result, types.RefreshOptions{Mode: types.SYNC})
|
||||
if err != nil {
|
||||
return result
|
||||
}
|
||||
|
||||
// Move the selection down by the number of commits we just
|
||||
// cherry-picked, to keep the same commit selected as before.
|
||||
// Don't do this if a rebase todo is selected, because in this
|
||||
// case we are in a rebase and the cherry-picked commits end up
|
||||
// below the selection.
|
||||
if commit := self.c.Contexts().LocalCommits.GetSelected(); commit != nil && !commit.IsTODO() {
|
||||
self.c.Contexts().LocalCommits.MoveSelection(len(cherryPickedCommits))
|
||||
self.c.Contexts().LocalCommits.FocusLine()
|
||||
}
|
||||
|
||||
// If we're in the cherry-picking state at this point, it must
|
||||
// be because there were conflicts. Don't clear the copied
|
||||
// commits in this case, since we might want to abort and try
|
||||
@@ -96,7 +115,17 @@ func (self *CherryPickHelper) Paste() error {
|
||||
if !isInCherryPick {
|
||||
self.getData().DidPaste = true
|
||||
self.rerender()
|
||||
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Pop(0); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.STASH, types.FILES},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
},
|
||||
|
||||
@@ -33,7 +33,8 @@ func (self *CredentialsHelper) PromptUserForCredential(passOrUname oscommands.Cr
|
||||
HandleConfirm: func(input string) error {
|
||||
ch <- input + "\n"
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
},
|
||||
HandleClose: func() error {
|
||||
ch <- "\n"
|
||||
|
||||
@@ -61,9 +61,8 @@ func (self *DiffHelper) GetUpdateTaskForRenderingCommitsDiff(commit *models.Comm
|
||||
args = append(args, path)
|
||||
}
|
||||
cmdObj := self.c.Git().Diff.DiffCmdObj(args)
|
||||
task := types.NewRunPtyTask(cmdObj.GetCmd())
|
||||
task.Prefix = style.FgYellow.Sprintf("%s %s-%s\n\n", self.c.Tr.ShowingDiffForRange, from.ShortRefName(), to.ShortRefName())
|
||||
return task
|
||||
prefix := style.FgYellow.Sprintf("%s %s-%s\n\n", self.c.Tr.ShowingDiffForRange, from.ShortRefName(), to.ShortRefName())
|
||||
return types.NewRunPtyTaskWithPrefix(cmdObj.GetCmd(), prefix)
|
||||
}
|
||||
|
||||
cmdObj := self.c.Git().Commit.ShowCmdObj(commit.Hash(), self.c.Modes().Filtering.GetPath())
|
||||
@@ -72,18 +71,19 @@ func (self *DiffHelper) GetUpdateTaskForRenderingCommitsDiff(commit *models.Comm
|
||||
|
||||
func (self *DiffHelper) ExitDiffMode() error {
|
||||
self.c.Modes().Diffing = diffing.New()
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *DiffHelper) RenderDiff() {
|
||||
args := self.DiffArgs()
|
||||
cmdObj := self.c.Git().Diff.DiffCmdObj(args)
|
||||
task := types.NewRunPtyTask(cmdObj.GetCmd())
|
||||
task.Prefix = style.FgMagenta.Sprintf(
|
||||
prefix := style.FgMagenta.Sprintf(
|
||||
"%s %s\n\n",
|
||||
self.c.Tr.ShowingGitDiff,
|
||||
"git diff "+strings.Join(args, " "),
|
||||
)
|
||||
task := types.NewRunPtyTaskWithPrefix(cmdObj.GetCmd(), prefix)
|
||||
|
||||
self.c.RenderToMainViews(types.RefreshMainOpts{
|
||||
Pair: self.c.MainViewPairs().Normal,
|
||||
|
||||
@@ -133,7 +133,7 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
|
||||
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
}
|
||||
|
||||
self.c.Contexts().LocalCommits.SetSelection(index)
|
||||
|
||||
@@ -32,20 +32,18 @@ func (self *GpgHelper) WithGpgHandling(cmdObj *oscommands.CmdObj, configKey git_
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope})
|
||||
|
||||
return err
|
||||
} else {
|
||||
return self.runAndStream(cmdObj, waitingStatus, onSuccess, refreshScope)
|
||||
}
|
||||
|
||||
return self.runAndStream(cmdObj, waitingStatus, onSuccess, refreshScope)
|
||||
}
|
||||
|
||||
func (self *GpgHelper) runAndStream(cmdObj *oscommands.CmdObj, waitingStatus string, onSuccess func() error, refreshScope []types.RefreshableView) error {
|
||||
return self.c.WithWaitingStatus(waitingStatus, func(gocui.Task) error {
|
||||
if err := cmdObj.StreamOutput().Run(); err != nil {
|
||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope})
|
||||
return fmt.Errorf(
|
||||
self.c.Tr.GitCommandFailed, self.c.UserConfig().Keybinding.Universal.ExtrasMenu,
|
||||
)
|
||||
@@ -57,6 +55,7 @@ func (self *GpgHelper) runAndStream(cmdObj *oscommands.CmdObj, waitingStatus str
|
||||
}
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: refreshScope})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type InlineStatusHelper struct {
|
||||
|
||||
windowHelper *WindowHelper
|
||||
contextsWithInlineStatus map[types.ContextKey]*inlineStatusInfo
|
||||
mutex *deadlock.Mutex
|
||||
mutex deadlock.Mutex
|
||||
}
|
||||
|
||||
func NewInlineStatusHelper(c *HelperCommon, windowHelper *WindowHelper) *InlineStatusHelper {
|
||||
@@ -23,7 +23,6 @@ func NewInlineStatusHelper(c *HelperCommon, windowHelper *WindowHelper) *InlineS
|
||||
c: c,
|
||||
windowHelper: windowHelper,
|
||||
contextsWithInlineStatus: make(map[types.ContextKey]*inlineStatusInfo),
|
||||
mutex: &deadlock.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,9 +150,8 @@ func isMergeConflictErr(errStr string) bool {
|
||||
}
|
||||
|
||||
func (self *MergeAndRebaseHelper) CheckMergeOrRebaseWithRefreshOptions(result error, refreshOptions types.RefreshOptions) error {
|
||||
if err := self.c.Refresh(refreshOptions); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(refreshOptions)
|
||||
|
||||
if result == nil {
|
||||
return nil
|
||||
} else if strings.Contains(result.Error(), "No changes - did you forget to use") {
|
||||
@@ -162,9 +161,8 @@ func (self *MergeAndRebaseHelper) CheckMergeOrRebaseWithRefreshOptions(result er
|
||||
} else if strings.Contains(result.Error(), "No rebase in progress?") {
|
||||
// assume in this case that we're already done
|
||||
return nil
|
||||
} else {
|
||||
return self.CheckForConflicts(result)
|
||||
}
|
||||
return self.CheckForConflicts(result)
|
||||
}
|
||||
|
||||
func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error {
|
||||
@@ -235,11 +233,9 @@ func (self *MergeAndRebaseHelper) PromptToContinueRebase() error {
|
||||
// Need to refresh the files to be really sure if this is the case.
|
||||
// We would otherwise be relying on lazygit's auto-refresh on focus,
|
||||
// but this is not supported by all terminals or on all platforms.
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
root := self.c.Contexts().Files.FileTreeViewModel.GetRoot()
|
||||
if root.GetHasUnstagedChanges() {
|
||||
@@ -458,7 +454,8 @@ func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranch
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,9 +167,9 @@ func (self *ModeHelper) ClearFiltering() error {
|
||||
self.c.State().GetRepoState().SetScreenMode(types.SCREEN_NORMAL)
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.COMMITS},
|
||||
Then: func() error {
|
||||
Then: func() {
|
||||
// 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
|
||||
@@ -178,9 +178,9 @@ func (self *ModeHelper) ClearFiltering() error {
|
||||
// before we entered filtering
|
||||
self.c.Contexts().LocalCommits.SelectCommitByHash(self.c.Modes().Filtering.GetSelectedCommitHash())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ModeHelper) SetSuppressRebasingMode(value bool) {
|
||||
|
||||
@@ -40,11 +40,9 @@ func (self *PatchBuildingHelper) Reset() error {
|
||||
self.Escape()
|
||||
}
|
||||
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.COMMIT_FILES},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
// refreshing the current context so that the secondary panel is hidden if necessary.
|
||||
self.c.PostRefreshUpdate(self.c.Context().Current())
|
||||
@@ -86,7 +84,7 @@ func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpt
|
||||
|
||||
oldState := context.GetState()
|
||||
|
||||
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState)
|
||||
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState, self.c.UserConfig().Gui.UseHunkModeInStagingView)
|
||||
context.SetState(state)
|
||||
if state == nil {
|
||||
self.Escape()
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewRefreshHelper(
|
||||
}
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
func (self *RefreshHelper) Refresh(options types.RefreshOptions) {
|
||||
if options.Mode == types.ASYNC && options.Then != nil {
|
||||
panic("RefreshOptions.Then doesn't work with mode ASYNC")
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
)
|
||||
}
|
||||
|
||||
f := func() error {
|
||||
f := func() {
|
||||
var scopeSet *set.Set[types.RefreshableView]
|
||||
if len(options.Scope) == 0 {
|
||||
// not refreshing staging/patch-building unless explicitly requested because we only need
|
||||
@@ -191,22 +191,19 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
wg.Wait()
|
||||
|
||||
if options.Then != nil {
|
||||
if err := options.Then(); err != nil {
|
||||
return err
|
||||
}
|
||||
options.Then()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if options.Mode == types.BLOCK_UI {
|
||||
self.c.OnUIThread(func() error {
|
||||
return f()
|
||||
f()
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
return f()
|
||||
f()
|
||||
}
|
||||
|
||||
func getScopeNames(scopes []types.RefreshableView) []string {
|
||||
@@ -308,7 +305,7 @@ func (self *RefreshHelper) determineCheckedOutBranchName() string {
|
||||
// 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 hash.
|
||||
// this will return an empty string.
|
||||
if branchName, err := self.c.Git().Branch.CurrentBranchName(); err == nil {
|
||||
return branchName
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
// loading a heap of commits is slow so we limit them whenever doing a reset
|
||||
self.c.Contexts().LocalCommits.SetLimitCommits(true)
|
||||
|
||||
_ = self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
}
|
||||
|
||||
localBranch, found := lo.Find(self.c.Model().Branches, func(branch *models.Branch) bool {
|
||||
@@ -56,9 +56,9 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
withCheckoutStatus := func(f func(gocui.Task) error) error {
|
||||
if found {
|
||||
return self.c.WithInlineStatus(localBranch, types.ItemOperationCheckingOut, context.LOCAL_BRANCHES_CONTEXT_KEY, f)
|
||||
} else {
|
||||
return self.c.WithWaitingStatus(waitingStatus, f)
|
||||
}
|
||||
|
||||
return self.c.WithWaitingStatus(waitingStatus, f)
|
||||
}
|
||||
|
||||
return withCheckoutStatus(func(gocui.Task) error {
|
||||
@@ -79,7 +79,7 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
|
||||
Prompt: self.c.Tr.AutoStashPrompt,
|
||||
HandleConfirm: func() error {
|
||||
return withCheckoutStatus(func(gocui.Task) error {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + ref); err != nil {
|
||||
if err := self.c.Git().Stash.Push(fmt.Sprintf(self.c.Tr.AutoStashForCheckout, ref)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := self.c.Git().Branch.Checkout(ref, cmdOptions); err != nil {
|
||||
@@ -145,12 +145,10 @@ func (self *RefsHelper) CheckoutRemoteBranch(fullBranchName string, localBranchN
|
||||
}
|
||||
// Do a sync refresh to make sure the new branch is visible,
|
||||
// so that we see an inline status when checking it out
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC,
|
||||
Scope: []types.RefreshableView{types.BRANCHES},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
return checkout(localBranchName)
|
||||
},
|
||||
},
|
||||
@@ -183,9 +181,7 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string
|
||||
// loading a heap of commits is slow so we limit them whenever doing a reset
|
||||
self.c.Contexts().LocalCommits.SetLimitCommits(true)
|
||||
|
||||
if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.BRANCHES, types.REFLOG, types.COMMITS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.BRANCHES, types.REFLOG, types.COMMITS}})
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -331,7 +327,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
||||
}
|
||||
}
|
||||
|
||||
refresh := func() error {
|
||||
refresh := func() {
|
||||
if self.c.Context().Current() != self.c.Contexts().Branches {
|
||||
self.c.Context().Push(self.c.Contexts().Branches, types.OnFocusOpts{})
|
||||
}
|
||||
@@ -339,7 +335,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
||||
self.c.Contexts().LocalCommits.SetSelection(0)
|
||||
self.c.Contexts().Branches.SetSelection(0)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
}
|
||||
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
@@ -359,20 +355,16 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
||||
Title: self.c.Tr.AutoStashTitle,
|
||||
Prompt: self.c.Tr.AutoStashPrompt,
|
||||
HandleConfirm: func() error {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + newBranchName); err != nil {
|
||||
if err := self.c.Git().Stash.Push(fmt.Sprintf(self.c.Tr.AutoStashForNewBranch, newBranchName)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := newBranchFunc(newBranchName, from); err != nil {
|
||||
return err
|
||||
}
|
||||
popErr := self.c.Git().Stash.Pop(0)
|
||||
err := self.c.Git().Stash.Pop(0)
|
||||
// Branch switch successful so re-render the UI even if the pop operation failed (e.g. conflict).
|
||||
refreshError := refresh()
|
||||
if popErr != nil {
|
||||
// An error from pop is the more important one to report to the user
|
||||
return popErr
|
||||
}
|
||||
return refreshError
|
||||
refresh()
|
||||
return err
|
||||
},
|
||||
})
|
||||
|
||||
@@ -382,7 +374,8 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest
|
||||
return err
|
||||
}
|
||||
|
||||
return refresh()
|
||||
refresh()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -396,7 +389,7 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
|
||||
return err
|
||||
}
|
||||
|
||||
withNewBranchNamePrompt := func(baseBranchName string, f func(string, string) error) error {
|
||||
withNewBranchNamePrompt := func(baseBranchName string, f func(string) error) error {
|
||||
prompt := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.NewBranchNameBranchOff,
|
||||
map[string]string{
|
||||
@@ -415,7 +408,7 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
|
||||
self.c.LogAction(self.c.Tr.MoveCommitsToNewBranch)
|
||||
newBranchName := SanitizedBranchName(response)
|
||||
return self.c.WithWaitingStatus(self.c.Tr.MovingCommitsToNewBranchStatus, func(gocui.Task) error {
|
||||
return f(currentBranch.Name, newBranchName)
|
||||
return f(newBranchName)
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -454,8 +447,8 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
|
||||
{
|
||||
Label: fmt.Sprintf(self.c.Tr.MoveCommitsToNewBranchFromBaseItem, shortBaseBranchName),
|
||||
OnPress: func() error {
|
||||
return withNewBranchNamePrompt(shortBaseBranchName, func(currentBranch string, newBranchName string) error {
|
||||
return self.moveCommitsToNewBranchOffOfMainBranch(currentBranch, newBranchName, baseBranchRef)
|
||||
return withNewBranchNamePrompt(shortBaseBranchName, func(newBranchName string) error {
|
||||
return self.moveCommitsToNewBranchOffOfMainBranch(newBranchName, baseBranchRef)
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -469,14 +462,14 @@ func (self *RefsHelper) MoveCommitsToNewBranch() error {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *RefsHelper) moveCommitsToNewBranchStackedOnCurrentBranch(currentBranch string, newBranchName string) error {
|
||||
func (self *RefsHelper) moveCommitsToNewBranchStackedOnCurrentBranch(newBranchName string) error {
|
||||
if err := self.c.Git().Branch.NewWithoutCheckout(newBranchName, "HEAD"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mustStash := IsWorkingTreeDirty(self.c.Model().Files)
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + currentBranch); err != nil {
|
||||
if err := self.c.Git().Stash.Push(fmt.Sprintf(self.c.Tr.AutoStashForNewBranch, newBranchName)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -498,17 +491,18 @@ func (self *RefsHelper) moveCommitsToNewBranchStackedOnCurrentBranch(currentBran
|
||||
self.c.Contexts().LocalCommits.SetSelection(0)
|
||||
self.c.Contexts().Branches.SetSelection(0)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefsHelper) moveCommitsToNewBranchOffOfMainBranch(currentBranch string, newBranchName string, baseBranchRef string) error {
|
||||
func (self *RefsHelper) moveCommitsToNewBranchOffOfMainBranch(newBranchName string, baseBranchRef string) error {
|
||||
commitsToCherryPick := lo.Filter(self.c.Model().Commits, func(commit *models.Commit, _ int) bool {
|
||||
return commit.Status == models.StatusUnpushed
|
||||
})
|
||||
|
||||
mustStash := IsWorkingTreeDirty(self.c.Model().Files)
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + currentBranch); err != nil {
|
||||
if err := self.c.Git().Stash.Push(fmt.Sprintf(self.c.Tr.AutoStashForNewBranch, newBranchName)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -536,7 +530,8 @@ func (self *RefsHelper) moveCommitsToNewBranchOffOfMainBranch(currentBranch stri
|
||||
self.c.Contexts().LocalCommits.SetSelection(0)
|
||||
self.c.Contexts().Branches.SetSelection(0)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefsHelper) CanMoveCommitsToNewBranch() *types.DisabledReason {
|
||||
@@ -563,7 +558,7 @@ func (self *RefsHelper) CanMoveCommitsToNewBranch() *types.DisabledReason {
|
||||
// SanitizedBranchName will remove all spaces in favor of a dash "-" to meet
|
||||
// git's branch naming requirement.
|
||||
func SanitizedBranchName(input string) string {
|
||||
return strings.Replace(input, " ", "-", -1)
|
||||
return strings.ReplaceAll(input, " ", "-")
|
||||
}
|
||||
|
||||
// Checks if the given branch name is a remote branch, and returns the name of
|
||||
|
||||
@@ -62,12 +62,13 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
|
||||
mainContext.GetMutex().Lock()
|
||||
secondaryContext.GetMutex().Lock()
|
||||
|
||||
hunkMode := self.c.UserConfig().Gui.UseHunkModeInStagingView
|
||||
mainContext.SetState(
|
||||
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState()),
|
||||
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState(), hunkMode),
|
||||
)
|
||||
|
||||
secondaryContext.SetState(
|
||||
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState()),
|
||||
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState(), hunkMode),
|
||||
)
|
||||
|
||||
mainState := mainContext.GetState()
|
||||
|
||||
@@ -385,9 +385,8 @@ func splitMainPanelSideBySide(args WindowArrangementArgs) bool {
|
||||
default:
|
||||
if args.Width < 200 && args.Height > 30 { // 2 80 character width panels + 40 width for side panel
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,11 +430,11 @@ func sidePanelChildren(args WindowArrangementArgs) func(width int, height int) [
|
||||
Window: window,
|
||||
Weight: 1,
|
||||
}
|
||||
} else {
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,33 +468,33 @@ func sidePanelChildren(args WindowArrangementArgs) func(width int, height int) [
|
||||
accordionBox(&boxlayout.Box{Window: "commits", Weight: 1}),
|
||||
accordionBox(getDefaultStashWindowBox(args)),
|
||||
}
|
||||
} else {
|
||||
squashedHeight := 1
|
||||
if height >= 21 {
|
||||
squashedHeight = 3
|
||||
}
|
||||
}
|
||||
|
||||
squashedSidePanelBox := func(window string) *boxlayout.Box {
|
||||
if window == args.CurrentSideWindow {
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Weight: 1,
|
||||
}
|
||||
} else {
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Size: squashedHeight,
|
||||
}
|
||||
squashedHeight := 1
|
||||
if height >= 21 {
|
||||
squashedHeight = 3
|
||||
}
|
||||
|
||||
squashedSidePanelBox := func(window string) *boxlayout.Box {
|
||||
if window == args.CurrentSideWindow {
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Weight: 1,
|
||||
}
|
||||
}
|
||||
|
||||
return []*boxlayout.Box{
|
||||
squashedSidePanelBox("status"),
|
||||
squashedSidePanelBox("files"),
|
||||
squashedSidePanelBox("branches"),
|
||||
squashedSidePanelBox("commits"),
|
||||
squashedSidePanelBox("stash"),
|
||||
return &boxlayout.Box{
|
||||
Window: window,
|
||||
Size: squashedHeight,
|
||||
}
|
||||
}
|
||||
|
||||
return []*boxlayout.Box{
|
||||
squashedSidePanelBox("status"),
|
||||
squashedSidePanelBox("files"),
|
||||
squashedSidePanelBox("branches"),
|
||||
squashedSidePanelBox("commits"),
|
||||
squashedSidePanelBox("stash"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +210,7 @@ func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) erro
|
||||
if err := self.c.Git().WorkingTree.StageAll(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := self.syncRefresh(); err != nil {
|
||||
return err
|
||||
}
|
||||
self.syncRefresh()
|
||||
|
||||
return retry()
|
||||
},
|
||||
@@ -222,8 +220,8 @@ func (self *WorkingTreeHelper) promptToStageAllAndRetry(retry func() error) erro
|
||||
}
|
||||
|
||||
// for when you need to refetch files before continuing an action. Runs synchronously.
|
||||
func (self *WorkingTreeHelper) syncRefresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
func (self *WorkingTreeHelper) syncRefresh() {
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
}
|
||||
|
||||
func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
||||
@@ -235,7 +233,7 @@ func (self *WorkingTreeHelper) prepareFilesForCommit() error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.syncRefresh()
|
||||
self.syncRefresh()
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -245,7 +243,7 @@ func (self *WorkingTreeHelper) commitPrefixConfigsForRepo() []config.CommitPrefi
|
||||
cfg, ok := self.c.UserConfig().Git.CommitPrefixes[self.c.Git().RepoPaths.RepoName()]
|
||||
if ok {
|
||||
return append(cfg, self.c.UserConfig().Git.CommitPrefix...)
|
||||
} else {
|
||||
return self.c.UserConfig().Git.CommitPrefix
|
||||
}
|
||||
|
||||
return self.c.UserConfig().Git.CommitPrefix
|
||||
}
|
||||
|
||||
@@ -132,24 +132,24 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
} else {
|
||||
// prompt for the new branch name where a blank means we just check out the branch
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.NewBranchName,
|
||||
HandleConfirm: func(branchName string) error {
|
||||
if branchName == "" {
|
||||
return errors.New(self.c.Tr.BranchNameCannotBeBlank)
|
||||
}
|
||||
|
||||
opts.Branch = branchName
|
||||
|
||||
return f()
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// prompt for the new branch name where a blank means we just check out the branch
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: self.c.Tr.NewBranchName,
|
||||
HandleConfirm: func(branchName string) error {
|
||||
if branchName == "" {
|
||||
return errors.New(self.c.Tr.BranchNameCannotBeBlank)
|
||||
}
|
||||
|
||||
opts.Branch = branchName
|
||||
|
||||
return f()
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -198,7 +198,8 @@ func (self *WorktreeHelper) Remove(worktree *models.Worktree, force bool) error
|
||||
}
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -214,7 +215,8 @@ func (self *WorktreeHelper) Detach(worktree *models.Worktree) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.WORKTREES, types.BRANCHES, types.FILES}})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -109,10 +109,11 @@ func (self *ListController) handleLineChangeAux(f func(int), change int) error {
|
||||
// we're not constantly re-rendering the main view.
|
||||
cursorMoved := before != after
|
||||
if cursorMoved {
|
||||
if change == -1 {
|
||||
switch change {
|
||||
case -1:
|
||||
checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig(),
|
||||
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
|
||||
} else if change == 1 {
|
||||
case 1:
|
||||
checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig(),
|
||||
self.context.ModelIndexToViewIndex(before), self.context.ModelIndexToViewIndex(after))
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func (self *ListControllerTrait[T]) itemRangeSelected(callbacks ...func([]T, int
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ListControllerTrait[T]) itemsSelected(callbacks ...func([]T) *types.DisabledReason) func() *types.DisabledReason { //nolint:unused
|
||||
func (self *ListControllerTrait[T]) itemsSelected(callbacks ...func([]T) *types.DisabledReason) func() *types.DisabledReason {
|
||||
return func() *types.DisabledReason {
|
||||
items, _, _ := self.getSelectedItems()
|
||||
if len(items) == 0 {
|
||||
|
||||
@@ -343,6 +343,10 @@ func (self *LocalCommitsController) fixup(selectedCommits []*models.Commit, star
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
||||
commitIdx := self.context().GetSelectedLineIdx()
|
||||
if self.c.Git().Config.NeedsGpgSubprocessForCommit() && !self.isHeadCommit(commitIdx) {
|
||||
return errors.New(self.c.Tr.DisabledForGPG)
|
||||
}
|
||||
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Hash())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -352,7 +356,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
|
||||
}
|
||||
self.c.Helpers().Commits.OpenCommitMessagePanel(
|
||||
&helpers.OpenCommitMessagePanelOpts{
|
||||
CommitIndex: self.context().GetSelectedLineIdx(),
|
||||
CommitIndex: commitIdx,
|
||||
InitialMessage: commitMessage,
|
||||
SummaryTitle: self.c.Tr.Actions.RewordCommit,
|
||||
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
|
||||
@@ -388,7 +392,8 @@ func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepat
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) handleReword(summary string, description string) error {
|
||||
@@ -404,7 +409,8 @@ func (self *LocalCommitsController) handleReword(summary string, description str
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -515,9 +521,8 @@ func (self *LocalCommitsController) edit(selectedCommits []*models.Commit, start
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||
err,
|
||||
types.RefreshOptions{
|
||||
Mode: types.BLOCK_UI, Then: func() error {
|
||||
Mode: types.BLOCK_UI, Then: func() {
|
||||
self.restoreSelectionRangeAndMode(selectionRangeAndMode)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -543,7 +548,7 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
|
||||
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() error {
|
||||
types.RefreshOptions{Mode: types.BLOCK_UI, Then: func() {
|
||||
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
|
||||
@@ -554,12 +559,11 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
|
||||
if len(todos) > 0 {
|
||||
err := self.updateTodos(todo.Edit, todos)
|
||||
if err != nil {
|
||||
return err
|
||||
self.c.Log.Errorf("error when updating todos: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
self.restoreSelectionRangeAndMode(selectionRangeAndMode)
|
||||
return nil
|
||||
}})
|
||||
})
|
||||
}
|
||||
@@ -638,9 +642,11 @@ func (self *LocalCommitsController) updateTodos(action todo.TodoCommand, selecte
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) rewordEnabled(commit *models.Commit) *types.DisabledReason {
|
||||
@@ -677,9 +683,10 @@ func (self *LocalCommitsController) moveDown(selectedCommits []*models.Commit, s
|
||||
}
|
||||
self.context().MoveSelection(1)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
||||
@@ -700,9 +707,10 @@ func (self *LocalCommitsController) moveUp(selectedCommits []*models.Commit, sta
|
||||
}
|
||||
self.context().MoveSelection(-1)
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.c.WithWaitingStatusSync(self.c.Tr.MovingStatus, func() error {
|
||||
@@ -717,27 +725,20 @@ func (self *LocalCommitsController) moveUp(selectedCommits []*models.Commit, sta
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
||||
var handleCommit func() error
|
||||
|
||||
if self.isSelectedHeadCommit() {
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.AmendCommitTitle,
|
||||
Prompt: self.c.Tr.AmendCommitPrompt,
|
||||
HandleConfirm: func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
if err := self.c.Helpers().AmendHelper.AmendHead(); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.AmendCommitTitle,
|
||||
Prompt: self.c.Tr.AmendCommitPrompt,
|
||||
HandleConfirm: func() error {
|
||||
handleCommit = func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
if err := self.c.Helpers().AmendHelper.AmendHead(); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
} else {
|
||||
handleCommit = func() error {
|
||||
return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.AmendCommit)
|
||||
@@ -745,7 +746,17 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if self.c.UserConfig().Gui.SkipAmendWarning {
|
||||
return handleCommit()
|
||||
}
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.AmendCommitTitle,
|
||||
Prompt: self.c.Tr.AmendCommitPrompt,
|
||||
HandleConfirm: handleCommit,
|
||||
})
|
||||
|
||||
return nil
|
||||
@@ -798,7 +809,8 @@ func (self *LocalCommitsController) resetAuthor(start, end int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -813,7 +825,8 @@ func (self *LocalCommitsController) setAuthor(start, end int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -831,7 +844,8 @@ func (self *LocalCommitsController) addCoAuthor(start, end int) error {
|
||||
if err := self.c.Git().Rebase.AddCommitCoAuthor(self.c.Model().Commits, start, end, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -859,14 +873,31 @@ func (self *LocalCommitsController) revert(commits []*models.Commit, start, end
|
||||
HandleConfirm: func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RevertCommit)
|
||||
return self.c.WithWaitingStatusSync(self.c.Tr.RevertingStatus, func() error {
|
||||
mustStash := helpers.IsWorkingTreeDirty(self.c.Model().Files)
|
||||
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Push(self.c.Tr.AutoStashForReverting); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
result := self.c.Git().Commit.Revert(hashes, isMerge)
|
||||
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(result); err != nil {
|
||||
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(result, types.RefreshOptions{Mode: types.SYNC}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.context().MoveSelection(len(commits))
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES},
|
||||
})
|
||||
self.context().FocusLine()
|
||||
|
||||
if mustStash {
|
||||
if err := self.c.Git().Stash.Pop(0); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.STASH, types.FILES},
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -902,7 +933,8 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
||||
}
|
||||
|
||||
self.context().MoveSelectedLine(1)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
return nil
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -1002,7 +1034,8 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc
|
||||
}
|
||||
|
||||
self.context().MoveSelectedLine(1)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
return nil
|
||||
})
|
||||
},
|
||||
OnSwitchToEditor: nil,
|
||||
@@ -1128,9 +1161,7 @@ func (self *LocalCommitsController) openSearch() error {
|
||||
// we usually lazyload these commits but now that we're searching we need to load them now
|
||||
if self.context().GetLimitCommits() {
|
||||
self.context().SetLimitCommits(false)
|
||||
if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}})
|
||||
}
|
||||
|
||||
return self.c.Helpers().Search.OpenSearchPrompt(self.context())
|
||||
@@ -1150,9 +1181,10 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
|
||||
}
|
||||
|
||||
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(gocui.Task) error {
|
||||
return self.c.Refresh(
|
||||
self.c.Refresh(
|
||||
types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}},
|
||||
)
|
||||
return nil
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -1202,12 +1234,13 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
|
||||
self.c.GetAppState().GitLogOrder = value
|
||||
self.c.SaveAppStateAndLogError()
|
||||
return self.c.WithWaitingStatus(self.c.Tr.LoadingCommits, func(gocui.Task) error {
|
||||
return self.c.Refresh(
|
||||
self.c.Refresh(
|
||||
types.RefreshOptions{
|
||||
Mode: types.SYNC,
|
||||
Scope: []types.RefreshableView{types.COMMITS},
|
||||
},
|
||||
)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1248,9 +1281,7 @@ func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) {
|
||||
context := self.context()
|
||||
if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
|
||||
context.SetLimitCommits(false)
|
||||
self.c.OnWorker(func(_ gocui.Task) error {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}})
|
||||
})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ func (self *MergeConflictsController) pickSelection(selection mergeconflicts.Sel
|
||||
}
|
||||
|
||||
if self.context().GetState().AllConflictsResolved() {
|
||||
return self.onLastConflictResolved()
|
||||
self.onLastConflictResolved()
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -314,10 +314,10 @@ func (self *MergeConflictsController) resolveConflict(selection mergeconflicts.S
|
||||
return true, os.WriteFile(state.GetPath(), []byte(content), 0o644)
|
||||
}
|
||||
|
||||
func (self *MergeConflictsController) onLastConflictResolved() error {
|
||||
func (self *MergeConflictsController) onLastConflictResolved() {
|
||||
// as part of refreshing files, we handle the situation where a file has had
|
||||
// its merge conflicts resolved.
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}})
|
||||
}
|
||||
|
||||
func (self *MergeConflictsController) withRenderAndFocus(f func() error) func() error {
|
||||
|
||||
@@ -116,16 +116,16 @@ func (self *PatchBuildingController) ToggleSelectionAndRefresh() error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.PATCH_BUILDING, types.COMMIT_FILES},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *PatchBuildingController) toggleSelection() error {
|
||||
self.context().GetMutex().Lock()
|
||||
defer self.context().GetMutex().Unlock()
|
||||
|
||||
toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
|
||||
filename := self.c.Contexts().CommitFiles.GetSelectedPath()
|
||||
if filename == "" {
|
||||
return nil
|
||||
@@ -133,19 +133,26 @@ func (self *PatchBuildingController) toggleSelection() error {
|
||||
|
||||
state := self.context().GetState()
|
||||
|
||||
// Get added/deleted lines in the selected patch range
|
||||
lineIndicesToToggle := state.LineIndicesOfAddedOrDeletedLinesInSelectedPatchRange()
|
||||
if len(lineIndicesToToggle) == 0 {
|
||||
// Only context lines or header lines selected, so nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
includedLineIndices, err := self.c.Git().Patch.PatchBuilder.GetFileIncLineIndices(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentLineIsStaged := lo.Contains(includedLineIndices, state.GetSelectedPatchLineIdx())
|
||||
if currentLineIsStaged {
|
||||
|
||||
toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
|
||||
firstSelectedChangeLineIsStaged := lo.Contains(includedLineIndices, lineIndicesToToggle[0])
|
||||
if firstSelectedChangeLineIsStaged {
|
||||
toggleFunc = self.c.Git().Patch.PatchBuilder.RemoveFileLineRange
|
||||
}
|
||||
|
||||
// add range of lines to those set for the file
|
||||
firstLineIdx, lastLineIdx := state.SelectedPatchRange()
|
||||
|
||||
if err := toggleFunc(filename, firstLineIdx, lastLineIdx); err != nil {
|
||||
if err := toggleFunc(filename, lineIndicesToToggle); err != nil {
|
||||
// might actually want to return an error here
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
@@ -154,6 +161,8 @@ func (self *PatchBuildingController) toggleSelection() error {
|
||||
state.SetLineSelectMode()
|
||||
}
|
||||
|
||||
state.SelectNextStageableLineOfSameIncludedState(self.context().GetIncludedLineIndices(), firstSelectedChangeLineIsStaged)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -161,7 +170,7 @@ func (self *PatchBuildingController) Escape() error {
|
||||
context := self.c.Contexts().CustomPatchBuilder
|
||||
state := context.GetState()
|
||||
|
||||
if state.SelectingRange() || state.SelectingHunk() {
|
||||
if state.SelectingRange() || state.SelectingHunkEnabledByUser() {
|
||||
state.SetLineSelectMode()
|
||||
self.c.PostRefreshUpdate(context)
|
||||
return nil
|
||||
|
||||
@@ -223,13 +223,13 @@ func (self *PatchExplorerController) HandleNextLineRange() error {
|
||||
}
|
||||
|
||||
func (self *PatchExplorerController) HandlePrevHunk() error {
|
||||
self.context.GetState().CycleHunk(false)
|
||||
self.context.GetState().SelectPreviousHunk()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *PatchExplorerController) HandleNextHunk() error {
|
||||
self.context.GetState().CycleHunk(true)
|
||||
self.context.GetState().SelectNextHunk()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func (self *RemoteBranchesController) context() *context.RemoteBranchesContext {
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) delete(selectedBranches []*models.RemoteBranch) error {
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(selectedBranches)
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(selectedBranches, true)
|
||||
}
|
||||
|
||||
func (self *RemoteBranchesController) merge(selectedBranch *models.RemoteBranch) error {
|
||||
@@ -150,7 +150,7 @@ func (self *RemoteBranchesController) createSortMenu() error {
|
||||
self.c.GetAppState().RemoteBranchSortOrder = sortOrder
|
||||
self.c.SaveAppStateAndLogError()
|
||||
self.c.Contexts().RemoteBranches.SetSelection(0)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.REMOTES}})
|
||||
self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.REMOTES}})
|
||||
}
|
||||
return nil
|
||||
},
|
||||
@@ -181,7 +181,8 @@ func (self *RemoteBranchesController) setAsUpstream(selectedBranch *models.Remot
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -148,12 +148,10 @@ func (self *RemotesController) add() error {
|
||||
// Do a sync refresh of the remotes so that we can select
|
||||
// the new one. Loading remotes is not expensive, so we can
|
||||
// afford it.
|
||||
if err := self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.REMOTES},
|
||||
Mode: types.SYNC,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
|
||||
// Select the new remote
|
||||
for idx, remote := range self.c.Model().Remotes {
|
||||
@@ -185,7 +183,8 @@ func (self *RemotesController) remove(remote *models.Remote) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -232,7 +231,8 @@ func (self *RemotesController) edit(remote *models.Remote) error {
|
||||
if err := self.c.Git().Remote.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
@@ -250,9 +250,10 @@ func (self *RemotesController) fetch(remote *models.Remote) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{
|
||||
self.c.Refresh(types.RefreshOptions{
|
||||
Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES},
|
||||
Mode: types.ASYNC,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,11 +88,11 @@ func (self *RenameSimilarityThresholdController) applyChange() error {
|
||||
switch currentContext.GetKey() {
|
||||
// we make an exception for our files context, because it actually need to refresh its state afterwards.
|
||||
case context.FILES_CONTEXT_KEY:
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
|
||||
default:
|
||||
currentContext.HandleRenderToMain()
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RenameSimilarityThresholdController) isShowingRenames() bool {
|
||||
|
||||
@@ -168,7 +168,7 @@ func (self *StagingController) EditFile() error {
|
||||
}
|
||||
|
||||
func (self *StagingController) Escape() error {
|
||||
if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunk() {
|
||||
if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunkEnabledByUser() {
|
||||
self.context.GetState().SetLineSelectMode()
|
||||
self.c.PostRefreshUpdate(self.context)
|
||||
return nil
|
||||
@@ -221,7 +221,8 @@ func (self *StagingController) applySelectionAndRefresh(reverse bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StagingController) applySelection(reverse bool) error {
|
||||
@@ -275,7 +276,8 @@ func (self *StagingController) EditHunkAndRefresh() error {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StagingController) editHunk() error {
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
@@ -82,8 +83,10 @@ func (self *StashController) GetOnRenderToMain() func() {
|
||||
if stashEntry == nil {
|
||||
task = types.NewRenderStringTask(self.c.Tr.NoStashEntries)
|
||||
} else {
|
||||
task = types.NewRunPtyTask(
|
||||
prefix := style.FgYellow.Sprintf("%s\n\n", stashEntry.Description())
|
||||
task = types.NewRunPtyTaskWithPrefix(
|
||||
self.c.Git().Stash.ShowStashEntryCmdObj(stashEntry.Index).GetCmd(),
|
||||
prefix,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -107,7 +110,7 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
|
||||
apply := func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.Stash)
|
||||
err := self.c.Git().Stash.Apply(stashEntry.Index)
|
||||
_ = self.postStashRefresh()
|
||||
self.postStashRefresh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -136,7 +139,7 @@ func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error
|
||||
pop := func() error {
|
||||
self.c.LogAction(self.c.Tr.Actions.Stash)
|
||||
err := self.c.Git().Stash.Pop(stashEntry.Index)
|
||||
_ = self.postStashRefresh()
|
||||
self.postStashRefresh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -170,11 +173,12 @@ func (self *StashController) handleStashDrop(stashEntries []*models.StashEntry)
|
||||
startIndex := stashEntries[0].Index
|
||||
for range stashEntries {
|
||||
err := self.c.Git().Stash.Drop(startIndex)
|
||||
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
self.context().CollapseRangeSelectionToTop()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
@@ -182,12 +186,12 @@ func (self *StashController) handleStashDrop(stashEntries []*models.StashEntry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StashController) postStashRefresh() error {
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
||||
func (self *StashController) postStashRefresh() {
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
|
||||
}
|
||||
|
||||
func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error {
|
||||
return self.c.Helpers().Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "")
|
||||
return self.c.Helpers().Refs.NewBranch(stashEntry.FullRefName(), stashEntry.Description(), "")
|
||||
}
|
||||
|
||||
func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntry) error {
|
||||
@@ -205,12 +209,13 @@ func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntr
|
||||
self.c.LogAction(self.c.Tr.Actions.RenameStash)
|
||||
err := self.c.Git().Stash.Rename(stashEntry.Index, response)
|
||||
if err != nil {
|
||||
_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
return err
|
||||
}
|
||||
self.context().SetSelection(0) // Select the renamed stash
|
||||
self.context().FocusLine()
|
||||
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user