mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-30 02:57:00 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a71b5f837 | ||
|
|
b62546c391 | ||
|
|
de8dc935a3 | ||
|
|
dd765801db | ||
|
|
111407d9a6 | ||
|
|
9f03f9e95d | ||
|
|
181b00b758 | ||
|
|
e1e4e1be1f | ||
|
|
fdeaf9cea0 | ||
|
|
b0a766cc95 | ||
|
|
f858460ab9 | ||
|
|
b2cbd93619 | ||
|
|
8da43af924 | ||
|
|
7edf629eeb | ||
|
|
1e8b8471ca | ||
|
|
095eb130e9 | ||
|
|
f08b3e9e1d | ||
|
|
8f3e59b78e | ||
|
|
eaf3bf0971 | ||
|
|
4883c867bb | ||
|
|
a58770ee1b | ||
|
|
7655f6864e | ||
|
|
286e5f4849 | ||
|
|
052974be65 | ||
|
|
85523402d6 | ||
|
|
f473d23d65 | ||
|
|
59a937ee7a | ||
|
|
53f8249ee1 | ||
|
|
f71274b601 | ||
|
|
f2fd435c05 | ||
|
|
4e361e1a87 | ||
|
|
696e78fcc8 | ||
|
|
b71aa5e23b | ||
|
|
72cf3efb1d | ||
|
|
ae610dcbb7 | ||
|
|
d11e11d179 | ||
|
|
825f5c0a91 | ||
|
|
26e3a93fc3 | ||
|
|
1ceb5a6b37 | ||
|
|
65b731f484 | ||
|
|
c6a7722066 | ||
|
|
1ab70ec645 | ||
|
|
e181de1180 | ||
|
|
c712b1d0fe | ||
|
|
c4e5995cb9 | ||
|
|
be3683ccc8 | ||
|
|
7e7309f97e | ||
|
|
d2b6f93858 | ||
|
|
a91fe517d3 | ||
|
|
8a328a553a | ||
|
|
3d56357294 | ||
|
|
9b2a0c4538 | ||
|
|
a04ad24a60 | ||
|
|
0d633896ae | ||
|
|
611fabde11 | ||
|
|
f8073c7188 | ||
|
|
4dadcd2ace | ||
|
|
b18f12ca0f | ||
|
|
c67979abbb | ||
|
|
0e489bb5cc | ||
|
|
647f533e71 | ||
|
|
b22149d832 | ||
|
|
396215a5c9 | ||
|
|
42c157a5e6 | ||
|
|
a793f709b6 | ||
|
|
f74551e464 | ||
|
|
e06b1cef60 |
@@ -21,6 +21,9 @@ changelog:
|
||||
- title: I18n 🌎
|
||||
labels:
|
||||
- i18n
|
||||
- title: Performance Improvements 📊
|
||||
labels:
|
||||
- performance
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- "*"
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
mkdir -p /tmp/code_coverage
|
||||
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
|
||||
- name: Upload code coverage artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
|
||||
path: /tmp/code_coverage
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
mkdir -p /tmp/code_coverage
|
||||
./scripts/run_integration_tests.sh
|
||||
- name: Upload code coverage artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
|
||||
path: /tmp/code_coverage
|
||||
@@ -184,7 +184,7 @@ jobs:
|
||||
with:
|
||||
mode: exactly
|
||||
count: 1
|
||||
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n"
|
||||
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n, performance"
|
||||
upload-coverage:
|
||||
# List all jobs that produce coverage files
|
||||
needs: [unit-tests, integration-tests]
|
||||
@@ -200,7 +200,7 @@ jobs:
|
||||
go-version: 1.22.x
|
||||
|
||||
- name: Download all coverage artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/code_coverage
|
||||
|
||||
|
||||
@@ -306,10 +306,10 @@ sudo eopkg install lazygit
|
||||
### Ubuntu
|
||||
|
||||
```sh
|
||||
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
|
||||
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
|
||||
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*')
|
||||
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
|
||||
tar xf lazygit.tar.gz lazygit
|
||||
sudo install lazygit /usr/local/bin
|
||||
sudo install lazygit -D -t /usr/local/bin/
|
||||
```
|
||||
|
||||
Verify the correct installation of lazygit:
|
||||
|
||||
@@ -246,6 +246,15 @@ gui:
|
||||
# One of 'dashboard' (default) | 'allBranchesLog'
|
||||
statusPanelView: dashboard
|
||||
|
||||
# If true, jump to the Files panel after popping a stash
|
||||
switchToFilesAfterStashPop: true
|
||||
|
||||
# If true, jump to the Files panel after applying a stash
|
||||
switchToFilesAfterStashApply: true
|
||||
|
||||
# If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead
|
||||
switchTabsWithPanelJumpKeys: false
|
||||
|
||||
# Config relating to git
|
||||
git:
|
||||
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md
|
||||
|
||||
@@ -2,7 +2,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
|
||||
|
||||
# Lazygit 按键绑定
|
||||
|
||||
_Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
_图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|
||||
|
||||
## 全局键绑定
|
||||
|
||||
@@ -11,28 +11,28 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
| `` <c-r> `` | 切换到最近的仓库 | |
|
||||
| `` <pgup> (fn+up/shift+k) `` | 向上滚动主面板 | |
|
||||
| `` <pgdown> (fn+down/shift+j) `` | 向下滚动主面板 | |
|
||||
| `` @ `` | 打开命令日志菜单 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` @ `` | 打开命令日志菜单 | 查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志 |
|
||||
| `` P `` | 推送 | 推送当前分支到它的上游。如果上游为配置,你可以在弹窗中配置上游分支。 |
|
||||
| `` p `` | 拉取 | 从当前分支的远程分支获取改动。如果上游为配置,你可以在弹窗中配置上游分支。 |
|
||||
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` } `` | 扩大差异视图中显示的上下文范围 | Increase the amount of the context shown around changes in the diff view. |
|
||||
| `` { `` | 缩小差异视图中显示的上下文范围 | Decrease the amount of the context shown around changes in the diff view. |
|
||||
| `` } `` | 扩大差异视图中显示的上下文范围 | 增加diff视图中围绕更改显示的上下文数量 |
|
||||
| `` { `` | 缩小差异视图中显示的上下文范围 | 减少diff视图中围绕更改显示的上下文数量 |
|
||||
| `` : `` | Execute shell command | Bring up a prompt where you can enter a shell command to execute. |
|
||||
| `` <c-p> `` | 查看自定义补丁选项 | |
|
||||
| `` m `` | 查看 合并/变基 选项 | View options to abort/continue/skip the current merge/rebase. |
|
||||
| `` R `` | 刷新 | Refresh the git state (i.e. run `git status`, `git branch`, etc in background to update the contents of panels). This does not run `git fetch`. |
|
||||
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||
| `` m `` | 查看 合并/变基 选项 | 查看当前合并或变基的中止、继续、跳过选项 |
|
||||
| `` R `` | 刷新 | 刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch` |
|
||||
| `` + `` | 下一屏模式(正常/半屏/全屏) | |
|
||||
| `` _ `` | 上一屏模式 | |
|
||||
| `` ? `` | 打开菜单 | |
|
||||
| `` <c-s> `` | 查看按路径过滤选项 | View options for filtering the commit log, so that only commits matching the filter are shown. |
|
||||
| `` W `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||
| `` <c-e> `` | 打开 diff 菜单 | View options relating to diffing two refs e.g. diffing against selected ref, entering ref to diff against, and reversing the diff direction. |
|
||||
| `` <c-s> `` | 查看按路径过滤选项 | 查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。 |
|
||||
| `` W `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 |
|
||||
| `` <c-e> `` | 打开 diff 菜单 | 查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。 |
|
||||
| `` q `` | 退出 | |
|
||||
| `` <esc> `` | 取消 | |
|
||||
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | Toggle whether or not whitespace changes are shown in the diff view. |
|
||||
| `` z `` | (通过 reflog)撤销「实验功能」 | The reflog will be used to determine what git command to run to undo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||
| `` <c-z> `` | (通过 reflog)重做「实验功能」 | The reflog will be used to determine what git command to run to redo the last git command. This does not include changes to the working tree; only commits are taken into consideration. |
|
||||
| `` <c-w> `` | 切换是否在差异视图中显示空白字符差异 | 切换是否在diff视图中显示空白更改 |
|
||||
| `` z `` | (通过 reflog)撤销「实验功能」 | Reflog将用于确定运行哪个git命令来撤消最后一个git命令。这并不包括对工作树的更改,只考虑提交。 |
|
||||
| `` <c-z> `` | (通过 reflog)重做「实验功能」 | Reflog将用于确定运行哪个git命令来重做上一个git命令。这并不包括对工作树的更改,只考虑提交。 |
|
||||
|
||||
## 列表面板导航
|
||||
|
||||
@@ -43,8 +43,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
| `` < `` | 滚动到顶部 | |
|
||||
| `` > `` | 滚动到底部 | |
|
||||
| `` v `` | 切换拖动选择 | |
|
||||
| `` <s-down> `` | Range select down | |
|
||||
| `` <s-up> `` | Range select up | |
|
||||
| `` <s-down> `` | 向下扩展选择范围 | |
|
||||
| `` <s-up> `` | 向上扩展选择范围 | |
|
||||
| `` / `` | 开始搜索 | |
|
||||
| `` H `` | 向左滚动 | |
|
||||
| `` L `` | 向右滚动 | |
|
||||
@@ -56,27 +56,17 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
|
||||
## Worktrees
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` n `` | New worktree | |
|
||||
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||
| `` o `` | Open in editor | |
|
||||
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 分支页面
|
||||
|
||||
@@ -84,42 +74,42 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将分支名称复制到剪贴板 | |
|
||||
| `` i `` | 显示 git-flow 选项 | |
|
||||
| `` <space> `` | 检出 | Checkout selected item. |
|
||||
| `` <space> `` | 检出 | 检出选中的项目 |
|
||||
| `` n `` | 新分支 | |
|
||||
| `` o `` | 创建抓取请求 | |
|
||||
| `` O `` | 创建抓取请求选项 | |
|
||||
| `` <c-y> `` | 将抓取请求 URL 复制到剪贴板 | |
|
||||
| `` c `` | 按名称检出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||
| `` F `` | 强制检出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` f `` | 从上游快进此分支 | Fast-forward selected branch from its upstream. |
|
||||
| `` c `` | 按名称检出 | 按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。 |
|
||||
| `` F `` | 强制检出 | 强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。 |
|
||||
| `` d `` | 删除 | 查看本地/远程分支的删除选项 |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||
| `` f `` | 从上游快进此分支 | 将当前分支直接移动到远程追踪分支的最新提交 |
|
||||
| `` T `` | 创建标签 | |
|
||||
| `` s `` | Sort order | |
|
||||
| `` s `` | 排序 | |
|
||||
| `` g `` | 查看重置选项 | |
|
||||
| `` R `` | 重命名分支 | |
|
||||
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 子提交
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <space> `` | 检出 | Checkout the selected commit as a detached HEAD. |
|
||||
| `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交的文件 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 子模块
|
||||
@@ -127,104 +117,114 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将子模块名称复制到剪贴板 | |
|
||||
| `` <enter> `` | Enter | 输入子模块 |
|
||||
| `` d `` | Remove | Remove the selected submodule and its corresponding directory. |
|
||||
| `` u `` | Update | 更新子模块 |
|
||||
| `` <enter> `` | 进入 | 输入子模块 |
|
||||
| `` d `` | 删除 | 删除选定的子模块及其相应的目录 |
|
||||
| `` u `` | 更新 | 更新子模块 |
|
||||
| `` n `` | 添加新的子模块 | |
|
||||
| `` e `` | 更新子模块 URL | |
|
||||
| `` i `` | Initialize | 初始化子模块 |
|
||||
| `` i `` | 初始化 | 初始化子模块 |
|
||||
| `` b `` | 查看批量子模块选项 | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 工作区
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` n `` | 新建工作树 | |
|
||||
| `` <space> `` | 切换 | 切换到选中的工作树 |
|
||||
| `` o `` | 在编辑器中编写 | |
|
||||
| `` d `` | 删除 | 删除选定的工作树。这将删除工作树的目录以及 .git 目录中有关工作树的元数据。 |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 提交
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将提交的 hash 复制到剪贴板 | |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
|
||||
| `` b `` | 查看二分查找选项 | |
|
||||
| `` s `` | 压缩 | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||
| `` 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. |
|
||||
| `` s `` | 压缩(Squash) | 将已选提交压缩到该提交之下。这些选定的提交的消息会附加到该提交的消息之下。 |
|
||||
| `` f `` | 修正(fixup) | 将选定的提交合并到其下面的提交中。与压缩类似,但所选提交的消息将被丢弃。 |
|
||||
| `` r `` | 改写提交 | 重写所选提交的消息。 |
|
||||
| `` R `` | 使用编辑器重命名提交 | |
|
||||
| `` d `` | 删除提交 | Drop the selected commit. This will remove the commit from the branch via a rebase. If the commit makes changes that later commits depend on, you may need to resolve merge conflicts. |
|
||||
| `` e `` | Edit (start interactive rebase) | 编辑提交 |
|
||||
| `` i `` | Start interactive rebase | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||
| `` p `` | Pick | 选择提交(变基过程中) |
|
||||
| `` d `` | 删除提交 | 删除选中的提交。这将通过变基从分支中删除该提交,如果该提交修改的内容依赖于后续的提交,则需要解决合并冲突。 |
|
||||
| `` e `` | 编辑(开始交互式变基) | 编辑提交 |
|
||||
| `` i `` | 开始交互式变基 | 为分支上的提交启动交互式变基。这将包括从 HEAD 提交到第一个合并提交或主分支提交的所有提交。
|
||||
如果您想从所选提交启动交互式变基,请按 `e`。 |
|
||||
| `` p `` | 拣选(Pick) | 选择提交(变基过程中) |
|
||||
| `` F `` | 为此提交创建修正 | 创建修正提交 |
|
||||
| `` S `` | Apply fixup commits | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
|
||||
| `` S `` | 应用该修复提交 | 压缩在所选提交之上的所有“fixup!”提交(自动压缩) |
|
||||
| `` <c-j> `` | 下移提交 | |
|
||||
| `` <c-k> `` | 上移提交 | |
|
||||
| `` V `` | 粘贴提交(拣选) | |
|
||||
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
|
||||
| `` A `` | 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 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). |
|
||||
| `` V `` | 粘贴提交(拣选) | |
|
||||
| `` B `` | 标记一个主提交用于变基 | 选择下一次变基的主提交。当您变基到一个分支时,只有高于主提交的提交才会被引入。这使用“git rebase --onto”命令。 |
|
||||
| `` A `` | 修补(Amend) | 用已暂存的变更来修补提交 |
|
||||
| `` a `` | 修补提交属性 | 设置或重置提交的作者,或添加其他作者。 |
|
||||
| `` t `` | 撤销(Revert) | 为所选提交创建还原提交,这会反向应用所选提交的更改。 |
|
||||
| `` T `` | 标签提交 | 创建一个新标签指向所选提交。你可以在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` <c-l> `` | 打开日志菜单 | 查看提交日志的选项,例如更改排序顺序、隐藏 git graph、显示整个 git graph。 |
|
||||
| `` <space> `` | 检出 | 检出所选择的提交作为分离HEAD。 |
|
||||
| `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 |
|
||||
| `` o `` | 在浏览器中打开提交 | |
|
||||
| `` n `` | 从提交创建新分支 | |
|
||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 复制提交(拣选) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交的文件 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 提交信息
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | 确认 | |
|
||||
| `` <esc> `` | 关闭 | |
|
||||
|
||||
## 提交文件
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||
| `` c `` | 检出 | 检出文件 |
|
||||
| `` d `` | Remove | 放弃对此文件的提交更改 |
|
||||
| `` o `` | 打开文件 | Open file in default application. |
|
||||
| `` e `` | Edit | Open file in external editor. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <space> `` | 补丁中包含的切换文件 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` a `` | Toggle all files | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||
| `` d `` | 删除 | 放弃对此文件的提交变更 |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` e `` | 编辑 | 使用外部编辑器打开文件 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <space> `` | 补丁中包含的切换文件 | 切换文件是否包含在自定义补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
|
||||
| `` a `` | 操作所有文件 | 添加或删除所有提交中的文件到自定义的补丁中。请参阅 https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches。 |
|
||||
| `` <enter> `` | 输入文件以将所选行添加到补丁中(或切换目录折叠) | 如果已选择一个文件,则Enter进入该文件,以便您可以向自定义补丁添加/删除单独的行。如果选择了目录,则切换目录。 |
|
||||
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 提交讯息
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | 确认 | |
|
||||
| `` <esc> `` | 关闭 | |
|
||||
|
||||
## 文件
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 将文件名复制到剪贴板 | |
|
||||
| `` <space> `` | 切换暂存状态 | Toggle staged for selected file. |
|
||||
| `` <c-b> `` | Filter files by status | |
|
||||
| `` y `` | Copy to clipboard | |
|
||||
| `` c `` | 提交更改 | Commit staged changes. |
|
||||
| `` w `` | 提交更改而无需预先提交钩子 | |
|
||||
| `` <space> `` | 切换暂存状态 | 为选定的文件切换暂存状态 |
|
||||
| `` <c-b> `` | 通过状态过滤文件 | |
|
||||
| `` y `` | 复制到剪贴板 | |
|
||||
| `` c `` | 提交变更 | 提交暂存文件 |
|
||||
| `` w `` | 提交变更而无需预先提交钩子 | |
|
||||
| `` A `` | 修补最后一次提交 | |
|
||||
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` e `` | Edit | Open file in external editor. |
|
||||
| `` o `` | 打开文件 | Open file in default application. |
|
||||
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
|
||||
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` e `` | 编辑 | 使用外部编辑器打开文件 |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` i `` | 忽略文件 | |
|
||||
| `` r `` | 刷新文件 | |
|
||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||
| `` S `` | 查看贮藏选项 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||
| `` a `` | 切换所有文件的暂存状态 | Toggle staged/unstaged for all files in working tree. |
|
||||
| `` <enter> `` | 暂存单个 块/行 用于文件, 或 折叠/展开 目录 | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||
| `` d `` | 查看'放弃更改'选项 | View options for discarding changes to the selected file. |
|
||||
| `` s `` | 贮藏 | 贮藏所有变更.若要使用其他贮藏变体,请使用查看贮藏选项快捷键 |
|
||||
| `` S `` | 查看贮藏选项 | 查看贮藏选项(例如:贮藏所有、贮藏已暂存变更、贮藏未暂存变更) |
|
||||
| `` a `` | 切换所有文件的暂存状态 | 切换工作区中所有文件的已暂存/未暂存状态 |
|
||||
| `` <enter> `` | 暂存单个 块/行 用于文件, 或 折叠/展开 目录 | 如果选中的是一个文件,则会进入到暂存视图,以便可以暂存单个代码块/行。如果选中的是一个目录,则会折叠/展开这个目录 |
|
||||
| `` d `` | 查看'放弃变更'选项 | 查看选中文件的放弃变更选项 |
|
||||
| `` g `` | 查看上游重置选项 | |
|
||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||
| `` ` `` | 切换文件树视图 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
||||
| `` f `` | 抓取 | Fetch changes from remote. |
|
||||
| `` D `` | 重置 | 查看工作树的重置选项(例如:清除工作树)。 |
|
||||
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
||||
| `` f `` | 抓取 | 从远程获取变更 |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 构建补丁中
|
||||
@@ -234,10 +234,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <left> `` | 选择上一个区块 | |
|
||||
| `` <right> `` | 选择下一个区块 | |
|
||||
| `` v `` | 切换拖动选择 | |
|
||||
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
||||
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||
| `` <c-o> `` | 将选中文本复制到剪贴板 | |
|
||||
| `` o `` | 打开文件 | Open file in default application. |
|
||||
| `` e `` | 编辑文件 | Open file in external editor. |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||
| `` <space> `` | 添加/移除 行到补丁 | |
|
||||
| `` <esc> `` | 退出逐行模式 | |
|
||||
| `` / `` | 开始搜索 | |
|
||||
@@ -246,15 +246,15 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | 检出 | Checkout the selected tag tag as a detached HEAD. |
|
||||
| `` n `` | 创建标签 | Create new tag from current commit. You'll be prompted to enter a tag name and optional description. |
|
||||
| `` d `` | Delete | View delete options for local/remote tag. |
|
||||
| `` P `` | 推送标签 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <space> `` | 检出 | 检出选择的标签作为分离的HEAD |
|
||||
| `` n `` | 创建标签 | 基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。 |
|
||||
| `` d `` | 删除 | 查看本地/远程标签的删除选项 |
|
||||
| `` P `` | 推送标签 | 推送选择的标签到远端。你将在弹窗中选择一个远端。 |
|
||||
| `` g `` | 重置 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 正在合并
|
||||
|
||||
@@ -266,10 +266,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <down> `` | 选择底部块 | |
|
||||
| `` <left> `` | 选择上一个冲突 | |
|
||||
| `` <right> `` | 选择下一个冲突 | |
|
||||
| `` z `` | 撤销 | Undo last merge conflict resolution. |
|
||||
| `` e `` | 编辑文件 | Open file in external editor. |
|
||||
| `` o `` | 打开文件 | Open file in default application. |
|
||||
| `` M `` | 打开外部合并工具 (git mergetool) | Run `git mergetool`. |
|
||||
| `` z `` | 撤销 | 撤消上次合并冲突解决 |
|
||||
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` M `` | 打开外部合并工具(git mergetool) | 执行 `git mergetool`. |
|
||||
| `` <esc> `` | 返回文件面板 | |
|
||||
|
||||
## 正在暂存
|
||||
@@ -279,19 +279,19 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <left> `` | 选择上一个区块 | |
|
||||
| `` <right> `` | 选择下一个区块 | |
|
||||
| `` v `` | 切换拖动选择 | |
|
||||
| `` a `` | 切换选择区块 | Toggle hunk selection mode. |
|
||||
| `` a `` | 切换选择代码块 | 切换代码块选择模式 |
|
||||
| `` <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. |
|
||||
| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 |
|
||||
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
|
||||
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
|
||||
| `` <esc> `` | 返回文件面板 | |
|
||||
| `` <tab> `` | 切换到其他面板 | Switch to other view (staged/unstaged changes). |
|
||||
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
|
||||
| `` c `` | 提交更改 | Commit staged changes. |
|
||||
| `` w `` | 提交更改而无需预先提交钩子 | |
|
||||
| `` C `` | 提交更改(使用编辑器编辑提交信息) | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
|
||||
| `` E `` | 编辑代码块 | 在外部编辑器中编辑选中的代码块 |
|
||||
| `` c `` | 提交变更 | 提交暂存文件 |
|
||||
| `` w `` | 提交变更而无需预先提交钩子 | |
|
||||
| `` C `` | 提交变更(使用编辑器编辑提交信息) | |
|
||||
| `` <c-f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` / `` | 开始搜索 | |
|
||||
|
||||
## 正常
|
||||
@@ -305,8 +305,8 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` o `` | 打开配置文件 | Open file in default application. |
|
||||
| `` e `` | 编辑配置文件 | Open file in external editor. |
|
||||
| `` o `` | 打开配置文件 | 使用默认程序打开该文件 |
|
||||
| `` e `` | 编辑配置文件 | 使用外部编辑器打开文件 |
|
||||
| `` u `` | 检查更新 | |
|
||||
| `` <enter> `` | 切换到最近的仓库 | |
|
||||
| `` a `` | 显示所有分支的日志 | |
|
||||
@@ -324,46 +324,46 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | 执行 | |
|
||||
| `` <esc> `` | 关闭 | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 贮藏
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | 应用 | Apply the stash entry to your working directory. |
|
||||
| `` g `` | 应用并删除 | Apply the stash entry to your working directory and remove the stash entry. |
|
||||
| `` d `` | 删除 | Remove the stash entry from the stash list. |
|
||||
| `` n `` | 新分支 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
|
||||
| `` r `` | Rename stash | |
|
||||
| `` <space> `` | 应用 | 将贮藏项应用到您的工作目录。 |
|
||||
| `` g `` | 应用并删除 | 将存储项应用到工作目录并删除存储项。 |
|
||||
| `` d `` | 删除 | 从贮藏列表中删除该贮藏项 |
|
||||
| `` n `` | 新分支 | 从选定的贮藏项创建一个新分支。这是通过 git 检查创建贮藏项的提交,从该提交创建一个新分支,然后将贮藏项作为附加提交应用到新分支来实现的。 |
|
||||
| `` r `` | 重命名贮藏 | |
|
||||
| `` <enter> `` | 查看提交的文件 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 远程分支
|
||||
|
||||
| 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. |
|
||||
| `` <space> `` | 检出 | 基于当前选中的远程分支检出一个新的本地分支,或者将远程分支作分离的HEAD。 |
|
||||
| `` n `` | 新分支 | |
|
||||
| `` M `` | 合并到当前检出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||
| `` u `` | Set as upstream | 设置为检出分支的上游 |
|
||||
| `` s `` | Sort order | |
|
||||
| `` g `` | 查看重置选项 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` M `` | 合并到当前检出的分支 | Merge selected branch into currently checked out branch. |
|
||||
| `` r `` | 将已检出的分支变基到该分支 | 将检出的分支变基到所选的分支上。 |
|
||||
| `` d `` | 删除 | 从远程删除远程分支。 |
|
||||
| `` u `` | 设置为上游 | 设置为检出分支的上游 |
|
||||
| `` s `` | 排序 | |
|
||||
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
|
||||
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
|
||||
| `` <enter> `` | 查看提交 | |
|
||||
| `` w `` | View worktree options | |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` w `` | 查看工作区选项 | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
## 远程页面
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` <enter> `` | View branches | |
|
||||
| `` <enter> `` | 查看分支 | |
|
||||
| `` n `` | 添加新的远程仓库 | |
|
||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||
| `` e `` | Edit | 编辑远程仓库 |
|
||||
| `` d `` | 删除 | 删除选中的远程。从远程跟踪远程分支的任何本地分支都不会受到影响。 |
|
||||
| `` e `` | 编辑 | 编辑远程仓库 |
|
||||
| `` f `` | 抓取 | 抓取远程仓库 |
|
||||
| `` / `` | Filter the current view by text | |
|
||||
| `` / `` | 通过文本过滤当前视图 | |
|
||||
|
||||
@@ -12,8 +12,8 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` <pgup> (fn+up/shift+k) `` | 向上捲動主面板 | |
|
||||
| `` <pgdown> (fn+down/shift+j) `` | 向下捲動主面板 | |
|
||||
| `` @ `` | 開啟命令記錄選單 | View options for the command log e.g. show/hide the command log and focus the command log. |
|
||||
| `` P `` | 推送 | Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` p `` | 拉取 | Pull changes from the remote for the current branch. If no upstream is configured, you will be prompted to configure an upstream branch. |
|
||||
| `` P `` | 推送 | 推送到遠端。如果沒有設定遠端,會開啟設定視窗。 |
|
||||
| `` p `` | 拉取 | 從遠端同步當前分支。如果沒有設定遠端,會開啟設定視窗。 |
|
||||
| `` ) `` | Increase rename similarity threshold | Increase the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` ( `` | Decrease rename similarity threshold | Decrease the similarity threshold for a deletion and addition pair to be treated as a rename. |
|
||||
| `` } `` | 增加差異檢視中顯示變更周圍上下文的大小 | Increase the amount of the context shown around changes in the diff view. |
|
||||
@@ -60,8 +60,8 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` v `` | 切換拖曳選擇 | |
|
||||
| `` a `` | 切換選擇程式碼塊 | Toggle hunk selection mode. |
|
||||
| `` <c-o> `` | 複製所選文本至剪貼簿 | |
|
||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||
| `` e `` | 編輯檔案 | Open file in external editor. |
|
||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
|
||||
| `` <esc> `` | 退出自訂補丁建立器 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -84,9 +84,9 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` <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`. |
|
||||
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
||||
| `` <esc> `` | 返回檔案面板 | |
|
||||
|
||||
## 主面板(預存)
|
||||
@@ -100,12 +100,12 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` <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. |
|
||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
|
||||
| `` <esc> `` | 返回檔案面板 | |
|
||||
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | Switch to other view (staged/unstaged changes). |
|
||||
| `` E `` | 編輯程式碼塊 | Edit selected hunk in external editor. |
|
||||
| `` c `` | 提交變更 | Commit staged changes. |
|
||||
| `` c `` | 提交變更 | 提交暫存區變更 |
|
||||
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
||||
| `` C `` | 使用 git 編輯器提交變更 | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
@@ -131,7 +131,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -156,7 +156,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
|-----|--------|-------------|
|
||||
| `` n `` | New worktree | |
|
||||
| `` <space> `` | Switch | Switch to the selected worktree. |
|
||||
| `` o `` | Open in editor | |
|
||||
| `` o `` | 在編輯器中開啟 | |
|
||||
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
|
||||
| `` / `` | 搜尋 | |
|
||||
|
||||
@@ -169,22 +169,22 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B
|
||||
| `` b `` | 查看二分選項 | |
|
||||
| `` s `` | 壓縮 (Squash) | Squash the selected commit into the commit below it. The selected commit's message will be appended to the commit below it. |
|
||||
| `` f `` | 修復 (Fixup) | Meld the selected commit into the commit below it. Similar to squash, but the selected commit's message will be discarded. |
|
||||
| `` r `` | 改寫提交 | Reword the selected commit's message. |
|
||||
| `` r `` | 改寫提交 | 改寫選中的提交訊息 |
|
||||
| `` R `` | 使用編輯器改寫提交 | |
|
||||
| `` 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.
|
||||
| `` e `` | 編輯(開始互動變基) | 編輯提交 |
|
||||
| `` i `` | 開始互動變基 | Start an interactive rebase for the commits on your branch. This will include all commits from the HEAD commit down to the first merge commit or main branch commit.
|
||||
If you would instead like to start an interactive rebase from the selected commit, press `e`. |
|
||||
| `` p `` | Pick | 挑選提交 (於變基過程中) |
|
||||
| `` p `` | 挑選 | 挑選提交 (於變基過程中) |
|
||||
| `` F `` | 建立修復提交 | 為此提交建立修復提交 |
|
||||
| `` S `` | 壓縮上方所有「fixup」提交(自動壓縮) | 是否壓縮上方 {{.commit}} 所有「fixup」提交? |
|
||||
| `` <c-j> `` | 向下移動提交 | |
|
||||
| `` <c-k> `` | 向上移動提交 | |
|
||||
| `` V `` | 貼上提交 (揀選) | |
|
||||
| `` B `` | 為了變基已標注提交為基準提交 | 請為了下一次變基選擇一項基準提交;此將執行 `git rebase --onto`。 |
|
||||
| `` A `` | Amend | 使用已預存的更改修正提交 |
|
||||
| `` A `` | 修改 | 使用已預存的更改修正提交 |
|
||||
| `` a `` | 設定/重設提交作者 | Set/Reset commit author or set co-author. |
|
||||
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||
| `` t `` | 還原 | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
|
||||
| `` T `` | 打標籤到提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
|
||||
| `` <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. |
|
||||
@@ -193,7 +193,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` n `` | 從提交建立新分支 | |
|
||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視所選項目的檔案 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -212,9 +212,9 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||
| `` c `` | 檢出 | 檢出檔案 |
|
||||
| `` d `` | Remove | Discard this commit's changes to this file. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes this file. |
|
||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||
| `` e `` | Edit | Open file in external editor. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||
| `` e `` | 編輯 | 使用外部編輯器開啟 |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <space> `` | 切換檔案是否包含在補丁中 | Toggle whether the file is included in the custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` a `` | 切換所有檔案是否包含在補丁中 | Add/remove all commit's files to custom patch. See https://github.com/jesseduffield/lazygit#rebase-magic-custom-patches. |
|
||||
| `` <enter> `` | 輸入檔案以將選定的行添加至補丁(或切換目錄折疊) | If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory. |
|
||||
@@ -246,7 +246,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
|
||||
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視提交 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -257,23 +257,23 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
|-----|--------|-------------|
|
||||
| `` <c-o> `` | 複製分支名稱到剪貼簿 | |
|
||||
| `` i `` | 顯示 git-flow 選項 | |
|
||||
| `` <space> `` | 檢出 | Checkout selected item. |
|
||||
| `` <space> `` | 檢出 | 檢出選定的項目。 |
|
||||
| `` n `` | 新分支 | |
|
||||
| `` o `` | 建立拉取請求 | |
|
||||
| `` O `` | 建立拉取請求選項 | |
|
||||
| `` <c-y> `` | 複製拉取請求的 URL 到剪貼板 | |
|
||||
| `` c `` | 根據名稱檢出 | Checkout by name. In the input box you can enter '-' to switch to the last branch. |
|
||||
| `` F `` | 強制檢出 | Force checkout selected branch. This will discard all local changes in your working directory before checking out the selected branch. |
|
||||
| `` d `` | Delete | View delete options for local/remote branch. |
|
||||
| `` d `` | 刪除 | View delete options for local/remote branch. |
|
||||
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` f `` | 從上游快進此分支 | Fast-forward selected branch from its upstream. |
|
||||
| `` f `` | 從上游快進此分支 | 從遠端快進所選的分支 |
|
||||
| `` T `` | 建立標籤 | |
|
||||
| `` s `` | Sort order | |
|
||||
| `` s `` | 排序規則 | |
|
||||
| `` g `` | 檢視重設選項 | |
|
||||
| `` R `` | 重新命名分支 | |
|
||||
| `` u `` | 檢視上游設定 | 檢視有關上游分支的設定(例如重設至上游) |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視提交 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -284,10 +284,10 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
|-----|--------|-------------|
|
||||
| `` <space> `` | 檢出 | Checkout the selected tag 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. |
|
||||
| `` d `` | 刪除 | View delete options for local/remote tag. |
|
||||
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
|
||||
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` g `` | 重設 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視提交 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
@@ -299,35 +299,35 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <c-o> `` | 複製檔案名稱到剪貼簿 | |
|
||||
| `` <space> `` | 切換預存 | Toggle staged for selected file. |
|
||||
| `` <c-b> `` | 篩選檔案 (預存/未預存) | |
|
||||
| `` y `` | Copy to clipboard | |
|
||||
| `` c `` | 提交變更 | Commit staged changes. |
|
||||
| `` y `` | 複製到剪貼簿 | |
|
||||
| `` c `` | 提交變更 | 提交暫存區變更 |
|
||||
| `` w `` | 沒有預提交 hook 就提交更改 | |
|
||||
| `` A `` | 修改上次提交 | |
|
||||
| `` C `` | 使用 git 編輯器提交變更 | |
|
||||
| `` <c-f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
|
||||
| `` e `` | Edit | Open file in external editor. |
|
||||
| `` o `` | 開啟檔案 | Open file in default application. |
|
||||
| `` e `` | 編輯 | 使用外部編輯器開啟 |
|
||||
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
|
||||
| `` i `` | 忽略或排除檔案 | |
|
||||
| `` r `` | 重新整理檔案 | |
|
||||
| `` s `` | Stash | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||
| `` s `` | 收藏 | Stash all changes. For other variations of stashing, use the view stash options keybinding. |
|
||||
| `` S `` | 檢視收藏選項 | View stash options (e.g. stash all, stash staged, stash unstaged). |
|
||||
| `` a `` | 全部預存/取消預存 | Toggle staged/unstaged for all files in working tree. |
|
||||
| `` <enter> `` | 選擇檔案中的單個程式碼塊/行,或展開/折疊目錄 | If the selected item is a file, focus the staging view so you can stage individual hunks/lines. If the selected item is a directory, collapse/expand it. |
|
||||
| `` d `` | Discard | View options for discarding changes to the selected file. |
|
||||
| `` g `` | 檢視上游重設選項 | |
|
||||
| `` D `` | Reset | View reset options for working tree (e.g. nuking the working tree). |
|
||||
| `` d `` | 捨棄 | 檢視選中變動進行捨棄復原 |
|
||||
| `` g `` | 檢視遠端重設選項 | |
|
||||
| `` D `` | 重設 | View reset options for working tree (e.g. nuking the working tree). |
|
||||
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` M `` | 開啟外部合併工具 (git mergetool) | Run `git mergetool`. |
|
||||
| `` f `` | 擷取 | Fetch changes from remote. |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` M `` | 開啟外部合併工具 | 執行 `git mergetool`。 |
|
||||
| `` f `` | 擷取 | 同步遠端異動 |
|
||||
| `` / `` | 搜尋 | |
|
||||
|
||||
## 狀態
|
||||
|
||||
| Key | Action | Info |
|
||||
|-----|--------|-------------|
|
||||
| `` o `` | 開啟設定檔案 | Open file in default application. |
|
||||
| `` e `` | 編輯設定檔案 | Open file in external editor. |
|
||||
| `` o `` | 開啟設定檔案 | 使用預設軟體開啟 |
|
||||
| `` e `` | 編輯設定檔案 | 使用外部編輯器開啟 |
|
||||
| `` u `` | 檢查更新 | |
|
||||
| `` <enter> `` | 切換到最近使用的版本庫 | |
|
||||
| `` a `` | 顯示所有分支日誌 | |
|
||||
@@ -346,7 +346,7 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` <enter> `` | View branches | |
|
||||
| `` n `` | 新增遠端 | |
|
||||
| `` d `` | Remove | Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected. |
|
||||
| `` e `` | Edit | 編輯遠端 |
|
||||
| `` e `` | 編輯 | 編輯遠端 |
|
||||
| `` f `` | 擷取 | 擷取遠端 |
|
||||
| `` / `` | 搜尋 | |
|
||||
|
||||
@@ -359,11 +359,11 @@ If you would instead like to start an interactive rebase from the selected commi
|
||||
| `` n `` | 新分支 | |
|
||||
| `` M `` | 合併到當前檢出的分支 | View options for merging the selected item into the current branch (regular merge, squash merge) |
|
||||
| `` r `` | 將已檢出的分支變基至此分支 | Rebase the checked-out branch onto the selected branch. |
|
||||
| `` d `` | Delete | Delete the remote branch from the remote. |
|
||||
| `` u `` | Set as upstream | 將此分支設為當前分支之上游 |
|
||||
| `` s `` | Sort order | |
|
||||
| `` d `` | 刪除 | Delete the remote branch from the remote. |
|
||||
| `` u `` | 設置為遠端 | 將此分支設為當前分支之遠端 |
|
||||
| `` s `` | 排序規則 | |
|
||||
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
|
||||
| `` <c-t> `` | Open external diff tool (git difftool) | |
|
||||
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
|
||||
| `` <enter> `` | 檢視提交 | |
|
||||
| `` w `` | 檢視工作目錄選項 | |
|
||||
| `` / `` | 搜尋 | |
|
||||
|
||||
@@ -16,7 +16,7 @@ require (
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240906064314-bfab49c720d7
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240928100326-393cf89a5d3f
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||
|
||||
@@ -188,8 +188,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
|
||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240906064314-bfab49c720d7 h1:QeLCKRAt4T6sBg5tSrOc4OojCuAcPxUA+4vNMPY4aH4=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240906064314-bfab49c720d7/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240928100326-393cf89a5d3f h1:ZzsAUDwPFLPITKLcJpMSqt/3rERdI8YRZKr2l0plrls=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20240928100326-393cf89a5d3f/go.mod h1:XtEbqCbn45keRXEu+OMZkjN5gw6AEob59afsgHjokZ8=
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||
|
||||
@@ -246,16 +246,18 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
||||
|
||||
// Takes the hash of some commit, and the hash of a fixup commit that was created
|
||||
// at the end of the branch, then moves the fixup commit down to right after the
|
||||
// original commit, changing its type to "fixup"
|
||||
// original commit, changing its type to "fixup" (only if ChangeToFixup is true)
|
||||
type MoveFixupCommitDownInstruction struct {
|
||||
OriginalHash string
|
||||
FixupHash string
|
||||
OriginalHash string
|
||||
FixupHash string
|
||||
ChangeToFixup bool
|
||||
}
|
||||
|
||||
func NewMoveFixupCommitDownInstruction(originalHash string, fixupHash string) Instruction {
|
||||
func NewMoveFixupCommitDownInstruction(originalHash string, fixupHash string, changeToFixup bool) Instruction {
|
||||
return &MoveFixupCommitDownInstruction{
|
||||
OriginalHash: originalHash,
|
||||
FixupHash: fixupHash,
|
||||
OriginalHash: originalHash,
|
||||
FixupHash: fixupHash,
|
||||
ChangeToFixup: changeToFixup,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +271,7 @@ func (self *MoveFixupCommitDownInstruction) SerializedInstructions() string {
|
||||
|
||||
func (self *MoveFixupCommitDownInstruction) run(common *common.Common) error {
|
||||
return handleInteractiveRebase(common, func(path string) error {
|
||||
return utils.MoveFixupCommitDown(path, self.OriginalHash, self.FixupHash, getCommentChar())
|
||||
return utils.MoveFixupCommitDown(path, self.OriginalHash, self.FixupHash, self.ChangeToFixup, getCommentChar())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/mgutz/str"
|
||||
@@ -260,3 +261,26 @@ func (self *BranchCommands) AllBranchesLogCmdObj() oscommands.ICmdObj {
|
||||
|
||||
return self.cmd.New(str.ToArgv(candidates[i])).DontLog()
|
||||
}
|
||||
|
||||
func (self *BranchCommands) IsBranchMerged(branch *models.Branch, mainBranches *MainBranches) (bool, error) {
|
||||
branchesToCheckAgainst := []string{"HEAD"}
|
||||
if branch.RemoteBranchStoredLocally() {
|
||||
branchesToCheckAgainst = append(branchesToCheckAgainst, fmt.Sprintf("%s@{upstream}", branch.Name))
|
||||
}
|
||||
branchesToCheckAgainst = append(branchesToCheckAgainst, mainBranches.Get()...)
|
||||
|
||||
cmdArgs := NewGitCmd("rev-list").
|
||||
Arg("--max-count=1").
|
||||
Arg(branch.Name).
|
||||
Arg(lo.Map(branchesToCheckAgainst, func(branch string, _ int) string {
|
||||
return fmt.Sprintf("^%s", branch)
|
||||
})...).
|
||||
ToArgv()
|
||||
|
||||
stdout, _, err := self.cmd.New(cmdArgs).RunWithOutputs()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return stdout == "", nil
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ type Author struct {
|
||||
|
||||
func (self *CommitCommands) GetCommitAuthor(commitHash string) (Author, error) {
|
||||
cmdArgs := NewGitCmd("show").
|
||||
Arg("--no-patch", "--pretty=format:'%an%x00%ae'", commitHash).
|
||||
Arg("--no-patch", "--pretty=format:%an%x00%ae", commitHash).
|
||||
ToArgv()
|
||||
|
||||
output, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
|
||||
@@ -230,7 +230,7 @@ func TestCommitShowCmdObj(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
filterPath string
|
||||
contextSize int
|
||||
contextSize uint64
|
||||
similarityThreshold int
|
||||
ignoreWhitespace bool
|
||||
extDiffCmd string
|
||||
|
||||
@@ -284,6 +284,11 @@ func (self *RebaseCommands) GitRebaseEditTodo(todosFileContent []byte) error {
|
||||
return cmdObj.Run()
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) getHashOfLastCommitMade() (string, error) {
|
||||
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
||||
return self.cmd.New(cmdArgs).RunWithOutput()
|
||||
}
|
||||
|
||||
// AmendTo amends the given commit with whatever files are staged
|
||||
func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) error {
|
||||
commit := commits[commitIndex]
|
||||
@@ -292,9 +297,7 @@ func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) e
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the hash of the commit we just created
|
||||
cmdArgs := NewGitCmd("rev-parse").Arg("--verify", "HEAD").ToArgv()
|
||||
fixupHash, err := self.cmd.New(cmdArgs).RunWithOutput()
|
||||
fixupHash, err := self.getHashOfLastCommitMade()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -302,7 +305,20 @@ func (self *RebaseCommands) AmendTo(commits []*models.Commit, commitIndex int) e
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
|
||||
overrideEditor: true,
|
||||
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Hash, fixupHash),
|
||||
instruction: daemon.NewMoveFixupCommitDownInstruction(commit.Hash, fixupHash, true),
|
||||
}).Run()
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) MoveFixupCommitDown(commits []*models.Commit, targetCommitIndex int) error {
|
||||
fixupHash, err := self.getHashOfLastCommitMade()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, targetCommitIndex+1),
|
||||
overrideEditor: true,
|
||||
instruction: daemon.NewMoveFixupCommitDownInstruction(commits[targetCommitIndex].Hash, fixupHash, false),
|
||||
}).Run()
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestStashStashEntryCmdObj(t *testing.T) {
|
||||
type scenario struct {
|
||||
testName string
|
||||
index int
|
||||
contextSize int
|
||||
contextSize uint64
|
||||
similarityThreshold int
|
||||
ignoreWhitespace bool
|
||||
expected []string
|
||||
|
||||
@@ -210,7 +210,7 @@ func TestWorkingTreeDiff(t *testing.T) {
|
||||
plain bool
|
||||
cached bool
|
||||
ignoreWhitespace bool
|
||||
contextSize int
|
||||
contextSize uint64
|
||||
similarityThreshold int
|
||||
runner *oscommands.FakeCmdObjRunner
|
||||
}
|
||||
@@ -352,7 +352,7 @@ func TestWorkingTreeShowFileDiff(t *testing.T) {
|
||||
reverse bool
|
||||
plain bool
|
||||
ignoreWhitespace bool
|
||||
contextSize int
|
||||
contextSize uint64
|
||||
runner *oscommands.FakeCmdObjRunner
|
||||
}
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@ type AppState struct {
|
||||
|
||||
HideCommandLog bool
|
||||
IgnoreWhitespaceInDiffView bool
|
||||
DiffContextSize int
|
||||
DiffContextSize uint64
|
||||
RenameSimilarityThreshold int
|
||||
LocalBranchSortOrder string
|
||||
RemoteBranchSortOrder string
|
||||
|
||||
@@ -161,6 +161,12 @@ type GuiConfig struct {
|
||||
// Status panel view.
|
||||
// One of 'dashboard' (default) | 'allBranchesLog'
|
||||
StatusPanelView string `yaml:"statusPanelView" jsonschema:"enum=dashboard,enum=allBranchesLog"`
|
||||
// If true, jump to the Files panel after popping a stash
|
||||
SwitchToFilesAfterStashPop bool `yaml:"switchToFilesAfterStashPop"`
|
||||
// If true, jump to the Files panel after applying a stash
|
||||
SwitchToFilesAfterStashApply bool `yaml:"switchToFilesAfterStashApply"`
|
||||
// If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead
|
||||
SwitchTabsWithPanelJumpKeys bool `yaml:"switchTabsWithPanelJumpKeys"`
|
||||
}
|
||||
|
||||
func (c *GuiConfig) UseFuzzySearch() bool {
|
||||
@@ -729,7 +735,10 @@ func GetDefaultConfig() *UserConfig {
|
||||
Frames: []string{"|", "/", "-", "\\"},
|
||||
Rate: 50,
|
||||
},
|
||||
StatusPanelView: "dashboard",
|
||||
StatusPanelView: "dashboard",
|
||||
SwitchToFilesAfterStashPop: true,
|
||||
SwitchToFilesAfterStashApply: true,
|
||||
SwitchTabsWithPanelJumpKeys: false,
|
||||
},
|
||||
Git: GitConfig{
|
||||
Paging: PagingConfig{
|
||||
|
||||
@@ -70,6 +70,8 @@ func (self *ContextMgr) Push(c types.Context, opts ...types.OnFocusOpts) {
|
||||
return
|
||||
}
|
||||
|
||||
gui.resetHelpersAndControllers()
|
||||
|
||||
contextsToDeactivate, contextToActivate := self.pushToContextStack(c)
|
||||
|
||||
for _, contextToDeactivate := range contextsToDeactivate {
|
||||
|
||||
@@ -14,6 +14,7 @@ type ConfirmationContext struct {
|
||||
type ConfirmationContextState struct {
|
||||
OnConfirm func() error
|
||||
OnClose func() error
|
||||
Multiline bool
|
||||
}
|
||||
|
||||
var _ types.Context = (*ConfirmationContext)(nil)
|
||||
|
||||
@@ -121,7 +121,10 @@ func (self *ListRenderer) insertNonModelItems(
|
||||
break
|
||||
}
|
||||
if item.Index+offset >= startIdx {
|
||||
padding := strings.Repeat(" ", columnPositions[item.Column])
|
||||
padding := ""
|
||||
if columnPositions != nil {
|
||||
padding = strings.Repeat(" ", columnPositions[item.Column])
|
||||
}
|
||||
lines = slices.Insert(lines, item.Index+offset-startIdx, padding+item.Content)
|
||||
}
|
||||
offset++
|
||||
|
||||
@@ -53,7 +53,7 @@ func NewPatchExplorerContext(
|
||||
func(selectedLineIdx int) error {
|
||||
ctx.GetMutex().Lock()
|
||||
defer ctx.GetMutex().Unlock()
|
||||
ctx.NavigateTo(ctx.c.Context().IsCurrent(ctx), selectedLineIdx)
|
||||
ctx.NavigateTo(selectedLineIdx)
|
||||
return nil
|
||||
}),
|
||||
)
|
||||
@@ -79,15 +79,15 @@ func (self *PatchExplorerContext) GetIncludedLineIndices() []int {
|
||||
return self.getIncludedLineIndices()
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) RenderAndFocus(isFocused bool) {
|
||||
self.setContent(isFocused)
|
||||
func (self *PatchExplorerContext) RenderAndFocus() {
|
||||
self.setContent()
|
||||
|
||||
self.FocusSelection()
|
||||
self.c.Render()
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) Render(isFocused bool) {
|
||||
self.setContent(isFocused)
|
||||
func (self *PatchExplorerContext) Render() {
|
||||
self.setContent()
|
||||
|
||||
self.c.Render()
|
||||
}
|
||||
@@ -97,8 +97,8 @@ func (self *PatchExplorerContext) Focus() {
|
||||
self.c.Render()
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) setContent(isFocused bool) {
|
||||
self.GetView().SetContent(self.GetContentToRender(isFocused))
|
||||
func (self *PatchExplorerContext) setContent() {
|
||||
self.GetView().SetContent(self.GetContentToRender())
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) FocusSelection() {
|
||||
@@ -119,19 +119,19 @@ func (self *PatchExplorerContext) FocusSelection() {
|
||||
view.SetCursorY(endIdx - newOriginY)
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) GetContentToRender(isFocused bool) string {
|
||||
func (self *PatchExplorerContext) GetContentToRender() string {
|
||||
if self.GetState() == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return self.GetState().RenderForLineIndices(isFocused, self.GetIncludedLineIndices())
|
||||
return self.GetState().RenderForLineIndices(self.GetIncludedLineIndices())
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) NavigateTo(isFocused bool, selectedLineIdx int) {
|
||||
func (self *PatchExplorerContext) NavigateTo(selectedLineIdx int) {
|
||||
self.GetState().SetLineSelectMode()
|
||||
self.GetState().SelectLine(selectedLineIdx)
|
||||
|
||||
self.RenderAndFocus(isFocused)
|
||||
self.RenderAndFocus()
|
||||
}
|
||||
|
||||
func (self *PatchExplorerContext) GetMutex() *deadlock.Mutex {
|
||||
|
||||
@@ -107,7 +107,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
Files: helpers.NewFilesHelper(helperCommon),
|
||||
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
|
||||
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper),
|
||||
BranchesHelper: helpers.NewBranchesHelper(helperCommon),
|
||||
BranchesHelper: helpers.NewBranchesHelper(helperCommon, worktreeHelper),
|
||||
GPG: helpers.NewGpgHelper(helperCommon),
|
||||
MergeAndRebase: rebaseHelper,
|
||||
MergeConflicts: mergeConflictsHelper,
|
||||
|
||||
@@ -3,7 +3,6 @@ package controllers
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
@@ -521,91 +520,16 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, KeepBranchSelectionIndex: true})
|
||||
}
|
||||
|
||||
func (self *BranchesController) checkedOutByOtherWorktree(branch *models.Branch) bool {
|
||||
return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees)
|
||||
}
|
||||
|
||||
func (self *BranchesController) promptWorktreeBranchDelete(selectedBranch *models.Branch) error {
|
||||
worktree, ok := self.worktreeForBranch(selectedBranch)
|
||||
if !ok {
|
||||
self.c.Log.Error("promptWorktreeBranchDelete out of sync with list of worktrees")
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: i18n
|
||||
title := utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree, map[string]string{
|
||||
"worktreeName": worktree.Name,
|
||||
"branchName": selectedBranch.Name,
|
||||
})
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: title,
|
||||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.SwitchToWorktree,
|
||||
OnPress: func() error {
|
||||
return self.c.Helpers().Worktree.Switch(worktree, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.DetachWorktree,
|
||||
Tooltip: self.c.Tr.DetachWorktreeTooltip,
|
||||
OnPress: func() error {
|
||||
return self.c.Helpers().Worktree.Detach(worktree)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.RemoveWorktree,
|
||||
OnPress: func() error {
|
||||
return self.c.Helpers().Worktree.Remove(worktree, false)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (self *BranchesController) localDelete(branch *models.Branch) error {
|
||||
if self.checkedOutByOtherWorktree(branch) {
|
||||
return self.promptWorktreeBranchDelete(branch)
|
||||
}
|
||||
|
||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(_ gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
|
||||
err := self.c.Git().Branch.LocalDelete(branch.Name, false)
|
||||
if err != nil && strings.Contains(err.Error(), "git branch -D ") {
|
||||
return self.forceDelete(branch)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
})
|
||||
return self.c.Helpers().BranchesHelper.ConfirmLocalDelete(branch)
|
||||
}
|
||||
|
||||
func (self *BranchesController) remoteDelete(branch *models.Branch) error {
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(branch.UpstreamRemote, branch.Name)
|
||||
return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(branch.UpstreamRemote, branch.UpstreamBranch)
|
||||
}
|
||||
|
||||
func (self *BranchesController) forceDelete(branch *models.Branch) error {
|
||||
title := self.c.Tr.ForceDeleteBranchTitle
|
||||
message := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.ForceDeleteBranchMessage,
|
||||
map[string]string{
|
||||
"selectedBranchName": branch.Name,
|
||||
},
|
||||
)
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: title,
|
||||
Prompt: message,
|
||||
HandleConfirm: func() error {
|
||||
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
func (self *BranchesController) localAndRemoteDelete(branch *models.Branch) error {
|
||||
return self.c.Helpers().BranchesHelper.ConfirmLocalAndRemoteDelete(branch)
|
||||
}
|
||||
|
||||
func (self *BranchesController) delete(branch *models.Branch) error {
|
||||
@@ -633,6 +557,19 @@ func (self *BranchesController) delete(branch *models.Branch) error {
|
||||
remoteDeleteItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.UpstreamNotSetError}
|
||||
}
|
||||
|
||||
deleteBothItem := &types.MenuItem{
|
||||
Label: self.c.Tr.DeleteLocalAndRemoteBranch,
|
||||
Key: 'b',
|
||||
OnPress: func() error {
|
||||
return self.localAndRemoteDelete(branch)
|
||||
},
|
||||
}
|
||||
if checkedOutBranch.Name == branch.Name {
|
||||
deleteBothItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.CantDeleteCheckOutBranch}
|
||||
} else if !branch.IsTrackingRemote() || branch.UpstreamGone {
|
||||
deleteBothItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.UpstreamNotSetError}
|
||||
}
|
||||
|
||||
menuTitle := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.DeleteBranchTitle,
|
||||
map[string]string{
|
||||
@@ -642,7 +579,7 @@ func (self *BranchesController) delete(branch *models.Branch) error {
|
||||
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: menuTitle,
|
||||
Items: []*types.MenuItem{localDeleteItem, remoteDeleteItem},
|
||||
Items: []*types.MenuItem{localDeleteItem, remoteDeleteItem, deleteBothItem},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,8 @@ func (self *CommitFilesController) toggleForPatch(selectedNodes []*filetree.Comm
|
||||
self.c.Git().Patch.PatchBuilder.Reset()
|
||||
}
|
||||
|
||||
return self.c.PostRefreshUpdate(self.context())
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -387,9 +388,7 @@ func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode
|
||||
func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *filetree.CommitFileNode) error {
|
||||
self.context().CommitFileTreeViewModel.ToggleCollapsed(node.GetPath())
|
||||
|
||||
if err := self.c.PostRefreshUpdate(self.context()); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -398,7 +397,8 @@ func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *file
|
||||
func (self *CommitFilesController) toggleTreeView() error {
|
||||
self.context().CommitFileTreeViewModel.ToggleShowTree()
|
||||
|
||||
return self.c.PostRefreshUpdate(self.context())
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: these functions are identical to those in files_controller.go (except for types) and
|
||||
|
||||
@@ -24,20 +24,54 @@ func NewConfirmationController(
|
||||
}
|
||||
|
||||
func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
bindings := []*types.Binding{}
|
||||
|
||||
if self.context().State.Multiline {
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
// Hard coding because this is always the button that adds a newline.
|
||||
Key: opts.GetKey("<enter>"),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In <enter> handler")
|
||||
self.c.Views().Confirmation.TextArea.TypeString("\n")
|
||||
self.c.Views().Confirmation.RenderTextArea()
|
||||
return nil
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: false,
|
||||
},
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.ConfirmInEditor),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In <alt-enter> handler")
|
||||
return self.context().State.OnConfirm()
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In single-line confirm handler")
|
||||
return self.context().State.OnConfirm()
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: func() error { return self.context().State.OnClose() },
|
||||
Description: self.c.Tr.CloseCancel,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
Handler: func() error {
|
||||
if len(self.c.Contexts().Suggestions.State.Suggestions) > 0 {
|
||||
@@ -54,7 +88,7 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
@@ -68,7 +69,9 @@ func (self *ContextLinesController) Increase() error {
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.AppState.DiffContextSize++
|
||||
if self.c.AppState.DiffContextSize < math.MaxUint64 {
|
||||
self.c.AppState.DiffContextSize++
|
||||
}
|
||||
return self.applyChange()
|
||||
}
|
||||
|
||||
@@ -76,14 +79,14 @@ func (self *ContextLinesController) Increase() error {
|
||||
}
|
||||
|
||||
func (self *ContextLinesController) Decrease() error {
|
||||
old_size := self.c.AppState.DiffContextSize
|
||||
|
||||
if self.isShowingDiff() && old_size > 1 {
|
||||
if self.isShowingDiff() {
|
||||
if err := self.checkCanChangeContext(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.AppState.DiffContextSize = old_size - 1
|
||||
if self.c.AppState.DiffContextSize > 0 {
|
||||
self.c.AppState.DiffContextSize--
|
||||
}
|
||||
return self.applyChange()
|
||||
}
|
||||
|
||||
|
||||
@@ -373,9 +373,7 @@ func (self *FilesController) optimisticChange(nodes []*filetree.FileNode, optimi
|
||||
}
|
||||
|
||||
if rerender {
|
||||
if err := self.c.PostRefreshUpdate(self.c.Contexts().Files); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -697,6 +695,13 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
||||
},
|
||||
Key: 'u',
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.FilterTrackedFiles,
|
||||
OnPress: func() error {
|
||||
return self.setStatusFiltering(filetree.DisplayTracked)
|
||||
},
|
||||
Key: 't',
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.ResetFilter,
|
||||
OnPress: func() error {
|
||||
@@ -710,7 +715,8 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
||||
|
||||
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
|
||||
self.context().FileTreeViewModel.SetStatusFilter(filter)
|
||||
return self.c.PostRefreshUpdate(self.context())
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) edit(nodes []*filetree.FileNode) error {
|
||||
@@ -949,9 +955,7 @@ func (self *FilesController) handleToggleDirCollapsed() error {
|
||||
|
||||
self.context().FileTreeViewModel.ToggleCollapsed(node.GetPath())
|
||||
|
||||
if err := self.c.PostRefreshUpdate(self.c.Contexts().Files); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -959,7 +963,8 @@ func (self *FilesController) handleToggleDirCollapsed() error {
|
||||
func (self *FilesController) toggleTreeView() error {
|
||||
self.context().FileTreeViewModel.ToggleShowTree()
|
||||
|
||||
return self.c.PostRefreshUpdate(self.context())
|
||||
self.c.PostRefreshUpdate(self.context())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) handleStashSave(stashFunc func(message string) error, action string) error {
|
||||
|
||||
@@ -4,20 +4,68 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
type BranchesHelper struct {
|
||||
c *HelperCommon
|
||||
c *HelperCommon
|
||||
worktreeHelper *WorktreeHelper
|
||||
}
|
||||
|
||||
func NewBranchesHelper(c *HelperCommon) *BranchesHelper {
|
||||
func NewBranchesHelper(c *HelperCommon, worktreeHelper *WorktreeHelper) *BranchesHelper {
|
||||
return &BranchesHelper{
|
||||
c: c,
|
||||
c: c,
|
||||
worktreeHelper: worktreeHelper,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) ConfirmLocalDelete(branch *models.Branch) error {
|
||||
if self.checkedOutByOtherWorktree(branch) {
|
||||
return self.promptWorktreeBranchDelete(branch)
|
||||
}
|
||||
|
||||
isMerged, err := self.c.Git().Branch.IsBranchMerged(branch, self.c.Model().MainBranches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
doDelete := func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(_ gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
|
||||
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
|
||||
})
|
||||
}
|
||||
|
||||
if isMerged {
|
||||
return doDelete()
|
||||
}
|
||||
|
||||
title := self.c.Tr.ForceDeleteBranchTitle
|
||||
message := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.ForceDeleteBranchMessage,
|
||||
map[string]string{
|
||||
"selectedBranchName": branch.Name,
|
||||
},
|
||||
)
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: title,
|
||||
Prompt: message,
|
||||
HandleConfirm: func() error {
|
||||
return doDelete()
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName string) error {
|
||||
title := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.DeleteBranchTitle,
|
||||
@@ -49,6 +97,104 @@ func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName st
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) ConfirmLocalAndRemoteDelete(branch *models.Branch) error {
|
||||
if self.checkedOutByOtherWorktree(branch) {
|
||||
return self.promptWorktreeBranchDelete(branch)
|
||||
}
|
||||
|
||||
isMerged, err := self.c.Git().Branch.IsBranchMerged(branch, self.c.Model().MainBranches)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prompt := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.DeleteLocalAndRemoteBranchPrompt,
|
||||
map[string]string{
|
||||
"localBranchName": branch.Name,
|
||||
"remoteBranchName": branch.UpstreamBranch,
|
||||
"remoteName": branch.UpstreamRemote,
|
||||
},
|
||||
)
|
||||
|
||||
if !isMerged {
|
||||
prompt += "\n\n" + utils.ResolvePlaceholderString(
|
||||
self.c.Tr.ForceDeleteBranchMessage,
|
||||
map[string]string{
|
||||
"selectedBranchName": branch.Name,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.DeleteLocalAndRemoteBranch,
|
||||
Prompt: prompt,
|
||||
HandleConfirm: func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task gocui.Task) error {
|
||||
// Delete the remote branch first so that we keep the local one
|
||||
// in case of failure
|
||||
self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
|
||||
if err := self.c.Git().Remote.DeleteRemoteBranch(task, branch.UpstreamRemote, branch.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
|
||||
if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ShortBranchName(fullBranchName string) string {
|
||||
return strings.TrimPrefix(strings.TrimPrefix(fullBranchName, "refs/heads/"), "refs/remotes/")
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) checkedOutByOtherWorktree(branch *models.Branch) bool {
|
||||
return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees)
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) worktreeForBranch(branch *models.Branch) (*models.Worktree, bool) {
|
||||
return git_commands.WorktreeForBranch(branch, self.c.Model().Worktrees)
|
||||
}
|
||||
|
||||
func (self *BranchesHelper) promptWorktreeBranchDelete(selectedBranch *models.Branch) error {
|
||||
worktree, ok := self.worktreeForBranch(selectedBranch)
|
||||
if !ok {
|
||||
self.c.Log.Error("promptWorktreeBranchDelete out of sync with list of worktrees")
|
||||
return nil
|
||||
}
|
||||
|
||||
title := utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree, map[string]string{
|
||||
"worktreeName": worktree.Name,
|
||||
"branchName": selectedBranch.Name,
|
||||
})
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: title,
|
||||
Items: []*types.MenuItem{
|
||||
{
|
||||
Label: self.c.Tr.SwitchToWorktree,
|
||||
OnPress: func() error {
|
||||
return self.worktreeHelper.Switch(worktree, context.LOCAL_BRANCHES_CONTEXT_KEY)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.DetachWorktree,
|
||||
Tooltip: self.c.Tr.DetachWorktreeTooltip,
|
||||
OnPress: func() error {
|
||||
return self.worktreeHelper.Detach(worktree)
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: self.c.Tr.RemoveWorktree,
|
||||
OnPress: func() error {
|
||||
return self.worktreeHelper.Remove(worktree, false)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -57,7 +57,10 @@ func (self *CherryPickHelper) CopyRange(commitsList []*models.Commit, context ty
|
||||
}
|
||||
}
|
||||
|
||||
return self.rerender()
|
||||
self.getData().DidPaste = false
|
||||
|
||||
self.rerender()
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied.
|
||||
@@ -102,7 +105,8 @@ func (self *CherryPickHelper) Paste() error {
|
||||
return err
|
||||
}
|
||||
if !isInRebase {
|
||||
return self.Reset()
|
||||
self.getData().DidPaste = true
|
||||
self.rerender()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -113,14 +117,15 @@ func (self *CherryPickHelper) Paste() error {
|
||||
}
|
||||
|
||||
func (self *CherryPickHelper) CanPaste() bool {
|
||||
return self.getData().Active()
|
||||
return self.getData().CanPaste()
|
||||
}
|
||||
|
||||
func (self *CherryPickHelper) Reset() error {
|
||||
self.getData().ContextKey = ""
|
||||
self.getData().CherryPickedCommits = nil
|
||||
|
||||
return self.rerender()
|
||||
self.rerender()
|
||||
return nil
|
||||
}
|
||||
|
||||
// you can only copy from one context at a time, because the order and position of commits matter
|
||||
@@ -136,16 +141,12 @@ func (self *CherryPickHelper) resetIfNecessary(context types.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *CherryPickHelper) rerender() error {
|
||||
func (self *CherryPickHelper) rerender() {
|
||||
for _, context := range []types.Context{
|
||||
self.c.Contexts().LocalCommits,
|
||||
self.c.Contexts().ReflogCommits,
|
||||
self.c.Contexts().SubCommits,
|
||||
} {
|
||||
if err := self.c.PostRefreshUpdate(context); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.PostRefreshUpdate(context)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
@@ -156,12 +157,14 @@ func (self *ConfirmationHelper) getPopupPanelWidth() int {
|
||||
func (self *ConfirmationHelper) prepareConfirmationPanel(
|
||||
opts types.ConfirmOpts,
|
||||
) {
|
||||
self.c.Views().Confirmation.Title = opts.Title
|
||||
self.c.Contexts().Confirmation.State.Multiline = opts.Multiline
|
||||
confirmationView := self.c.Views().Confirmation
|
||||
confirmationView.Title = opts.Title
|
||||
// for now we do not support wrapping in our editor
|
||||
self.c.Views().Confirmation.Wrap = !opts.Editable
|
||||
self.c.Views().Confirmation.FgColor = theme.GocuiDefaultTextColor
|
||||
self.c.Views().Confirmation.Mask = runeForMask(opts.Mask)
|
||||
self.c.Views().Confirmation.SetOrigin(0, 0)
|
||||
confirmationView.Wrap = !opts.Editable
|
||||
confirmationView.FgColor = theme.GocuiDefaultTextColor
|
||||
confirmationView.Mask = runeForMask(opts.Mask)
|
||||
confirmationView.SetOrigin(0, 0)
|
||||
|
||||
suggestionsContext := self.c.Contexts().Suggestions
|
||||
suggestionsContext.State.FindSuggestions = opts.FindSuggestionsFunc
|
||||
@@ -206,6 +209,7 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
self.prepareConfirmationPanel(
|
||||
types.ConfirmOpts{
|
||||
Title: opts.Title,
|
||||
Multiline: opts.Multiline,
|
||||
Prompt: opts.Prompt,
|
||||
FindSuggestionsFunc: opts.FindSuggestionsFunc,
|
||||
Editable: opts.Editable,
|
||||
@@ -213,6 +217,14 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
})
|
||||
confirmationView := self.c.Views().Confirmation
|
||||
confirmationView.Editable = opts.Editable
|
||||
if opts.Multiline {
|
||||
confirmationView.Subtitle = utils.ResolvePlaceholderString(
|
||||
self.c.Tr.PressToSubmit,
|
||||
map[string]string{"Key": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor},
|
||||
)
|
||||
} else {
|
||||
confirmationView.Subtitle = ""
|
||||
}
|
||||
|
||||
if opts.Editable {
|
||||
textArea := confirmationView.TextArea
|
||||
@@ -221,7 +233,7 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
confirmationView.RenderTextArea()
|
||||
} else {
|
||||
self.c.ResetViewOrigin(confirmationView)
|
||||
self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(underlineLinks(opts.Prompt)))
|
||||
self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(opts.Prompt))
|
||||
}
|
||||
|
||||
self.setKeyBindings(cancel, opts)
|
||||
@@ -233,28 +245,6 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
self.c.Context().Push(self.c.Contexts().Confirmation)
|
||||
}
|
||||
|
||||
func underlineLinks(text string) string {
|
||||
result := ""
|
||||
remaining := text
|
||||
for {
|
||||
linkStart := strings.Index(remaining, "https://")
|
||||
if linkStart == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
linkEnd := strings.IndexAny(remaining[linkStart:], " \n>")
|
||||
if linkEnd == -1 {
|
||||
linkEnd = len(remaining)
|
||||
} else {
|
||||
linkEnd += linkStart
|
||||
}
|
||||
underlinedLink := style.PrintSimpleHyperlink(remaining[linkStart:linkEnd])
|
||||
result += remaining[:linkStart] + underlinedLink
|
||||
remaining = remaining[linkEnd:]
|
||||
}
|
||||
return result + remaining
|
||||
}
|
||||
|
||||
func (self *ConfirmationHelper) setKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) {
|
||||
var onConfirm func() error
|
||||
if opts.HandleConfirmPrompt != nil {
|
||||
@@ -385,7 +375,16 @@ func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types
|
||||
prompt = self.c.Views().Confirmation.TextArea.GetContent()
|
||||
wrap = false
|
||||
}
|
||||
panelHeight := getMessageHeight(wrap, prompt, panelWidth) + suggestionsViewHeight
|
||||
|
||||
multiline := self.c.Contexts().Confirmation.State.Multiline
|
||||
inputHeight := getMessageHeight(wrap, prompt, panelWidth)
|
||||
|
||||
minMultilineHeight := 5
|
||||
if multiline && inputHeight < minMultilineHeight {
|
||||
inputHeight = minMultilineHeight
|
||||
}
|
||||
|
||||
panelHeight := inputHeight + suggestionsViewHeight
|
||||
x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext)
|
||||
confirmationViewBottom := y1 - suggestionsViewHeight
|
||||
_, _ = self.c.GocuiGui().SetView(self.c.Views().Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gookit/color"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/xo/terminfo"
|
||||
)
|
||||
|
||||
func Test_underlineLinks(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
text string
|
||||
expectedResult string
|
||||
}{
|
||||
{
|
||||
name: "empty string",
|
||||
text: "",
|
||||
expectedResult: "",
|
||||
},
|
||||
{
|
||||
name: "no links",
|
||||
text: "abc",
|
||||
expectedResult: "abc",
|
||||
},
|
||||
{
|
||||
name: "entire string is a link",
|
||||
text: "https://example.com",
|
||||
expectedResult: "\x1b]8;;https://example.com\x1b\\https://example.com\x1b]8;;\x1b\\",
|
||||
},
|
||||
{
|
||||
name: "link preceded and followed by text",
|
||||
text: "bla https://example.com xyz",
|
||||
expectedResult: "bla \x1b]8;;https://example.com\x1b\\https://example.com\x1b]8;;\x1b\\ xyz",
|
||||
},
|
||||
{
|
||||
name: "more than one link",
|
||||
text: "bla https://link1 blubb https://link2 xyz",
|
||||
expectedResult: "bla \x1b]8;;https://link1\x1b\\https://link1\x1b]8;;\x1b\\ blubb \x1b]8;;https://link2\x1b\\https://link2\x1b]8;;\x1b\\ xyz",
|
||||
},
|
||||
{
|
||||
name: "link in angle brackets",
|
||||
text: "See <https://example.com> for details",
|
||||
expectedResult: "See <\x1b]8;;https://example.com\x1b\\https://example.com\x1b]8;;\x1b\\> for details",
|
||||
},
|
||||
{
|
||||
name: "link followed by newline",
|
||||
text: "URL: https://example.com\nNext line",
|
||||
expectedResult: "URL: \x1b]8;;https://example.com\x1b\\https://example.com\x1b]8;;\x1b\\\nNext line",
|
||||
},
|
||||
}
|
||||
|
||||
oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelMillions)
|
||||
defer color.ForceSetColorLevel(oldColorLevel)
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
result := underlineLinks(s.text)
|
||||
assert.Equal(t, s.expectedResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -487,5 +487,6 @@ func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranch
|
||||
|
||||
func (self *MergeAndRebaseHelper) ResetMarkedBaseCommit() error {
|
||||
self.c.Modes().MarkedBaseCommit.Reset()
|
||||
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ func (self *PatchBuildingHelper) Reset() error {
|
||||
}
|
||||
|
||||
// refreshing the current context so that the secondary panel is hidden if necessary.
|
||||
return self.c.PostRefreshUpdate(self.c.Context().Current())
|
||||
self.c.PostRefreshUpdate(self.c.Context().Current())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpts) {
|
||||
@@ -97,7 +98,7 @@ func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpt
|
||||
return
|
||||
}
|
||||
|
||||
mainContent := context.GetContentToRender(true)
|
||||
mainContent := context.GetContentToRender()
|
||||
|
||||
self.c.Contexts().CustomPatchBuilder.FocusSelection()
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.STASH) {
|
||||
refresh("stash", func() { _ = self.refreshStashEntries() })
|
||||
refresh("stash", func() { self.refreshStashEntries() })
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.TAGS) {
|
||||
@@ -169,7 +169,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.WORKTREES) && !includeWorktreesWithBranches {
|
||||
refresh("worktrees", func() { _ = self.refreshWorktrees() })
|
||||
refresh("worktrees", func() { self.refreshWorktrees() })
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.STAGING) {
|
||||
@@ -343,7 +343,8 @@ func (self *RefreshHelper) refreshCommitsWithLimit() error {
|
||||
self.c.Model().WorkingTreeStateAtLastCommitRefresh = self.c.Git().Status.WorkingTreeState()
|
||||
self.c.Model().CheckedOutBranch = checkedOutBranchName
|
||||
|
||||
return self.refreshView(self.c.Contexts().LocalCommits)
|
||||
self.refreshView(self.c.Contexts().LocalCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshSubCommitsWithLimit() error {
|
||||
@@ -368,7 +369,8 @@ func (self *RefreshHelper) refreshSubCommitsWithLimit() error {
|
||||
self.c.Model().SubCommits = commits
|
||||
self.RefreshAuthors(commits)
|
||||
|
||||
return self.refreshView(self.c.Contexts().SubCommits)
|
||||
self.refreshView(self.c.Contexts().SubCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) RefreshAuthors(commits []*models.Commit) {
|
||||
@@ -397,7 +399,8 @@ func (self *RefreshHelper) refreshCommitFilesContext() error {
|
||||
self.c.Model().CommitFiles = files
|
||||
self.c.Contexts().CommitFiles.CommitFileTreeViewModel.SetTree()
|
||||
|
||||
return self.refreshView(self.c.Contexts().CommitFiles)
|
||||
self.refreshView(self.c.Contexts().CommitFiles)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshRebaseCommits() error {
|
||||
@@ -411,7 +414,8 @@ func (self *RefreshHelper) refreshRebaseCommits() error {
|
||||
self.c.Model().Commits = updatedCommits
|
||||
self.c.Model().WorkingTreeStateAtLastCommitRefresh = self.c.Git().Status.WorkingTreeState()
|
||||
|
||||
return self.refreshView(self.c.Contexts().LocalCommits)
|
||||
self.refreshView(self.c.Contexts().LocalCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshTags() error {
|
||||
@@ -422,7 +426,8 @@ func (self *RefreshHelper) refreshTags() error {
|
||||
|
||||
self.c.Model().Tags = tags
|
||||
|
||||
return self.refreshView(self.c.Contexts().Tags)
|
||||
self.refreshView(self.c.Contexts().Tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshStateSubmoduleConfigs() error {
|
||||
@@ -482,9 +487,7 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
|
||||
|
||||
if refreshWorktrees {
|
||||
self.loadWorktrees()
|
||||
if err := self.refreshView(self.c.Contexts().Worktrees); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
self.refreshView(self.c.Contexts().Worktrees)
|
||||
}
|
||||
|
||||
if !keepBranchSelectionIndex && prevSelectedBranch != nil {
|
||||
@@ -495,9 +498,7 @@ func (self *RefreshHelper) refreshBranches(refreshWorktrees bool, keepBranchSele
|
||||
}
|
||||
}
|
||||
|
||||
if err := self.refreshView(self.c.Contexts().Branches); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
self.refreshView(self.c.Contexts().Branches)
|
||||
|
||||
// Need to re-render the commits view because the visualization of local
|
||||
// branch heads might have changed
|
||||
@@ -525,14 +526,8 @@ func (self *RefreshHelper) refreshFilesAndSubmodules() error {
|
||||
}
|
||||
|
||||
self.c.OnUIThread(func() error {
|
||||
if err := self.refreshView(self.c.Contexts().Submodules); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
|
||||
if err := self.refreshView(self.c.Contexts().Files); err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
|
||||
self.refreshView(self.c.Contexts().Submodules)
|
||||
self.refreshView(self.c.Contexts().Files)
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -653,7 +648,8 @@ func (self *RefreshHelper) refreshReflogCommits() error {
|
||||
model.FilteredReflogCommits = model.ReflogCommits
|
||||
}
|
||||
|
||||
return self.refreshView(self.c.Contexts().ReflogCommits)
|
||||
self.refreshView(self.c.Contexts().ReflogCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshRemotes() error {
|
||||
@@ -677,14 +673,8 @@ func (self *RefreshHelper) refreshRemotes() error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := self.refreshView(self.c.Contexts().Remotes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.refreshView(self.c.Contexts().RemoteBranches); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.refreshView(self.c.Contexts().Remotes)
|
||||
self.refreshView(self.c.Contexts().RemoteBranches)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -698,23 +688,20 @@ func (self *RefreshHelper) loadWorktrees() {
|
||||
self.c.Model().Worktrees = worktrees
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshWorktrees() error {
|
||||
func (self *RefreshHelper) refreshWorktrees() {
|
||||
self.loadWorktrees()
|
||||
|
||||
// need to refresh branches because the branches view shows worktrees against
|
||||
// branches
|
||||
if err := self.refreshView(self.c.Contexts().Branches); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.refreshView(self.c.Contexts().Worktrees)
|
||||
self.refreshView(self.c.Contexts().Branches)
|
||||
self.refreshView(self.c.Contexts().Worktrees)
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshStashEntries() error {
|
||||
func (self *RefreshHelper) refreshStashEntries() {
|
||||
self.c.Model().StashEntries = self.c.Git().Loaders.StashLoader.
|
||||
GetStashEntries(self.c.Modes().Filtering.GetPath())
|
||||
|
||||
return self.refreshView(self.c.Contexts().Stash)
|
||||
self.refreshView(self.c.Contexts().Stash)
|
||||
}
|
||||
|
||||
// never call this on its own, it should only be called from within refreshCommits()
|
||||
@@ -754,12 +741,12 @@ func (self *RefreshHelper) refForLog() string {
|
||||
return bisectInfo.GetStartHash()
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshView(context types.Context) error {
|
||||
func (self *RefreshHelper) refreshView(context types.Context) {
|
||||
// Re-applying the filter must be done before re-rendering the view, so that
|
||||
// the filtered list model is up to date for rendering.
|
||||
self.searchHelper.ReApplyFilter(context)
|
||||
|
||||
err := self.c.PostRefreshUpdate(context)
|
||||
self.c.PostRefreshUpdate(context)
|
||||
|
||||
self.c.AfterLayout(func() error {
|
||||
// Re-applying the search must be done after re-rendering the view though,
|
||||
@@ -773,6 +760,4 @@ func (self *RefreshHelper) refreshView(context types.Context) error {
|
||||
self.searchHelper.ReApplySearch(context)
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ func (self *SearchHelper) Cancel() {
|
||||
switch context := state.Context.(type) {
|
||||
case types.IFilterableContext:
|
||||
context.ClearFilter()
|
||||
_ = self.c.PostRefreshUpdate(context)
|
||||
self.c.PostRefreshUpdate(context)
|
||||
case types.ISearchableContext:
|
||||
context.ClearSearchString()
|
||||
context.GetView().ClearSearch()
|
||||
@@ -231,7 +231,7 @@ func (self *SearchHelper) OnPromptContentChanged(searchString string) {
|
||||
context.SetSelection(0)
|
||||
context.GetView().SetOriginY(0)
|
||||
context.SetFilter(searchString, self.c.UserConfig().Gui.UseFuzzySearch())
|
||||
_ = self.c.PostRefreshUpdate(context)
|
||||
self.c.PostRefreshUpdate(context)
|
||||
case types.ISearchableContext:
|
||||
// do nothing
|
||||
default:
|
||||
|
||||
@@ -73,8 +73,8 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
|
||||
mainState := mainContext.GetState()
|
||||
secondaryState := secondaryContext.GetState()
|
||||
|
||||
mainContent := mainContext.GetContentToRender(!secondaryFocused)
|
||||
secondaryContent := secondaryContext.GetContentToRender(secondaryFocused)
|
||||
mainContent := mainContext.GetContentToRender()
|
||||
secondaryContent := secondaryContext.GetContentToRender()
|
||||
|
||||
mainContext.GetMutex().Unlock()
|
||||
secondaryContext.GetMutex().Unlock()
|
||||
|
||||
@@ -67,10 +67,7 @@ func (self *SubCommitsHelper) ViewSubCommits(opts ViewSubCommitsOpts) error {
|
||||
subCommitsContext.GetView().ClearSearch()
|
||||
subCommitsContext.GetView().TitlePrefix = opts.Context.GetView().TitlePrefix
|
||||
|
||||
err = self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
||||
|
||||
self.c.Context().Push(self.c.Contexts().SubCommits)
|
||||
return nil
|
||||
|
||||
@@ -49,7 +49,8 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt
|
||||
|
||||
func (self *JumpToSideWindowController) goToSideWindow(window string) func() error {
|
||||
return func() error {
|
||||
if self.c.Helpers().Window.CurrentWindow() == window {
|
||||
sideWindowAlreadyActive := self.c.Helpers().Window.CurrentWindow() == window
|
||||
if sideWindowAlreadyActive && self.c.UserConfig().Gui.SwitchTabsWithPanelJumpKeys {
|
||||
return self.nextTabFunc()
|
||||
}
|
||||
|
||||
|
||||
@@ -895,6 +895,10 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.moveFixupCommitToOwnerStackedBranch(commit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.context().MoveSelectedLine(1)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
})
|
||||
@@ -924,6 +928,50 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err
|
||||
})
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) moveFixupCommitToOwnerStackedBranch(targetCommit *models.Commit) error {
|
||||
if self.c.Git().Version.IsOlderThan(2, 38, 0) {
|
||||
// Git 2.38.0 introduced the `rebase.updateRefs` config option. Don't
|
||||
// move the commit down with older versions, as it would break the stack.
|
||||
return nil
|
||||
}
|
||||
|
||||
if self.c.Git().Status.WorkingTreeState() != enums.REBASE_MODE_NONE {
|
||||
// Can't move commits while rebasing
|
||||
return nil
|
||||
}
|
||||
|
||||
if targetCommit.Status == models.StatusMerged {
|
||||
// Target commit is already on main. It's a bit questionable that we
|
||||
// allow creating a fixup commit for it in the first place, but we
|
||||
// always did, so why restrict that now; however, it doesn't make sense
|
||||
// to move the created fixup commit down in that case.
|
||||
return nil
|
||||
}
|
||||
|
||||
if !self.c.Git().Config.GetRebaseUpdateRefs() {
|
||||
// If the user has disabled rebase.updateRefs, we don't move the fixup
|
||||
// because this would break the stack of branches (presumably they like
|
||||
// to manage it themselves manually, or something).
|
||||
return nil
|
||||
}
|
||||
|
||||
headOfOwnerBranchIdx := -1
|
||||
for i := self.context().GetSelectedLineIdx(); i > 0; i-- {
|
||||
if lo.SomeBy(self.c.Model().Branches, func(b *models.Branch) bool {
|
||||
return b.CommitHash == self.c.Model().Commits[i].Hash
|
||||
}) {
|
||||
headOfOwnerBranchIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if headOfOwnerBranchIdx == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return self.c.Git().Rebase.MoveFixupCommitDown(self.c.Model().Commits, headOfOwnerBranchIdx)
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, includeFileChanges bool) error {
|
||||
commitMessage, err := self.c.Git().Commit.GetCommitMessage(commit.Hash)
|
||||
if err != nil {
|
||||
@@ -947,6 +995,10 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc
|
||||
return err
|
||||
}
|
||||
|
||||
if err := self.moveFixupCommitToOwnerStackedBranch(commit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.context().MoveSelectedLine(1)
|
||||
return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC})
|
||||
})
|
||||
@@ -1125,10 +1177,9 @@ func (self *LocalCommitsController) handleOpenLogMenu() error {
|
||||
return func() error {
|
||||
self.c.GetAppState().GitLogShowGraph = value
|
||||
self.c.SaveAppStateAndLogError()
|
||||
if err := self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits); err != nil {
|
||||
return err
|
||||
}
|
||||
return self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
@@ -1234,7 +1285,8 @@ func (self *LocalCommitsController) markAsBaseCommit(commit *models.Commit) erro
|
||||
} else {
|
||||
self.c.Modes().MarkedBaseCommit.SetHash(commit.Hash)
|
||||
}
|
||||
return self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().LocalCommits)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) isHeadCommit(idx int) bool {
|
||||
|
||||
@@ -160,7 +160,8 @@ func (self *PatchBuildingController) Escape() error {
|
||||
|
||||
if state.SelectingRange() || state.SelectingHunk() {
|
||||
state.SetLineSelectMode()
|
||||
return self.c.PostRefreshUpdate(context)
|
||||
self.c.PostRefreshUpdate(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
self.c.Helpers().PatchBuilding.Escape()
|
||||
|
||||
@@ -302,7 +302,7 @@ func (self *PatchExplorerController) withRenderAndFocus(f func() error) func() e
|
||||
return err
|
||||
}
|
||||
|
||||
self.context.RenderAndFocus(self.isFocused())
|
||||
self.context.RenderAndFocus()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ func (self *QuitActions) Escape() error {
|
||||
if listContext, ok := currentContext.(types.IListContext); ok {
|
||||
if listContext.GetList().IsSelectingRange() {
|
||||
listContext.GetList().CancelRangeSelect()
|
||||
return self.c.PostRefreshUpdate(listContext)
|
||||
self.c.PostRefreshUpdate(listContext)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,7 @@ func (self *RemotesController) enter(remote *models.Remote) error {
|
||||
remoteBranchesContext.SetParentContext(self.Context())
|
||||
remoteBranchesContext.GetView().TitlePrefix = self.Context().GetView().TitlePrefix
|
||||
|
||||
if err := self.c.PostRefreshUpdate(remoteBranchesContext); err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.PostRefreshUpdate(remoteBranchesContext)
|
||||
|
||||
self.c.Context().Push(remoteBranchesContext)
|
||||
return nil
|
||||
|
||||
@@ -132,8 +132,6 @@ func (self *StagingController) GetOnFocusLost() func(types.OnFocusLostOpts) {
|
||||
if opts.NewContextKey != self.otherContext.GetKey() {
|
||||
self.c.Views().Staging.Wrap = true
|
||||
self.c.Views().StagingSecondary.Wrap = true
|
||||
self.c.Contexts().Staging.Render(false)
|
||||
self.c.Contexts().StagingSecondary.Render(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,7 +166,8 @@ func (self *StagingController) EditFile() error {
|
||||
func (self *StagingController) Escape() error {
|
||||
if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunk() {
|
||||
self.context.GetState().SetLineSelectMode()
|
||||
return self.c.PostRefreshUpdate(self.context)
|
||||
self.c.PostRefreshUpdate(self.context)
|
||||
return nil
|
||||
}
|
||||
|
||||
self.c.Context().Pop()
|
||||
|
||||
@@ -111,7 +111,9 @@ func (self *StashController) handleStashApply(stashEntry *models.StashEntry) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Context().Push(self.c.Contexts().Files)
|
||||
if self.c.UserConfig().Gui.SwitchToFilesAfterStashApply {
|
||||
self.c.Context().Push(self.c.Contexts().Files)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -138,7 +140,9 @@ func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.Context().Push(self.c.Contexts().Files)
|
||||
if self.c.UserConfig().Gui.SwitchToFilesAfterStashPop {
|
||||
self.c.Context().Push(self.c.Contexts().Files)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -208,12 +208,12 @@ func (self *StatusController) showDashboard() {
|
||||
[]string{
|
||||
lazygitTitle(),
|
||||
fmt.Sprintf("Copyright %d Jesse Duffield", time.Now().Year()),
|
||||
fmt.Sprintf("Keybindings: %s", style.PrintSimpleHyperlink(fmt.Sprintf(constants.Links.Docs.Keybindings, versionStr))),
|
||||
fmt.Sprintf("Config Options: %s", style.PrintSimpleHyperlink(fmt.Sprintf(constants.Links.Docs.Config, versionStr))),
|
||||
fmt.Sprintf("Tutorial: %s", style.PrintSimpleHyperlink(constants.Links.Docs.Tutorial)),
|
||||
fmt.Sprintf("Raise an Issue: %s", style.PrintSimpleHyperlink(constants.Links.Issues)),
|
||||
fmt.Sprintf("Release Notes: %s", style.PrintSimpleHyperlink(constants.Links.Releases)),
|
||||
style.FgMagenta.Sprintf("Become a sponsor: %s", style.PrintSimpleHyperlink(constants.Links.Donate)), // caffeine ain't free
|
||||
fmt.Sprintf("Keybindings: %s", fmt.Sprintf(constants.Links.Docs.Keybindings, versionStr)),
|
||||
fmt.Sprintf("Config Options: %s", fmt.Sprintf(constants.Links.Docs.Config, versionStr)),
|
||||
fmt.Sprintf("Tutorial: %s", constants.Links.Docs.Tutorial),
|
||||
fmt.Sprintf("Raise an Issue: %s", constants.Links.Issues),
|
||||
fmt.Sprintf("Release Notes: %s", constants.Links.Releases),
|
||||
style.FgMagenta.Sprintf("Become a sponsor: %s", constants.Links.Donate), // caffeine ain't free
|
||||
}, "\n\n") + "\n"
|
||||
|
||||
self.c.RenderToMainViews(types.RefreshMainOpts{
|
||||
|
||||
@@ -162,10 +162,7 @@ func (self *FilesController) createResetMenu() error {
|
||||
|
||||
func (self *FilesController) animateExplosion() {
|
||||
self.Explode(self.c.Views().Files, func() {
|
||||
err := self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
if err != nil {
|
||||
self.c.Log.Error(err)
|
||||
}
|
||||
self.c.PostRefreshUpdate(self.c.Contexts().Files)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
func BuildTreeFromFiles(files []*models.File) *Node[models.File] {
|
||||
root := &Node[models.File]{}
|
||||
|
||||
childrenMapsByNode := make(map[*Node[models.File]]map[string]*Node[models.File])
|
||||
|
||||
var curr *Node[models.File]
|
||||
for _, file := range files {
|
||||
splitPath := split(file.Name)
|
||||
@@ -23,11 +25,19 @@ func BuildTreeFromFiles(files []*models.File) *Node[models.File] {
|
||||
}
|
||||
|
||||
path := join(splitPath[:i+1])
|
||||
for _, existingChild := range curr.Children {
|
||||
if existingChild.Path == path {
|
||||
curr = existingChild
|
||||
continue outer
|
||||
}
|
||||
|
||||
var currNodeChildrenMap map[string]*Node[models.File]
|
||||
var isCurrNodeMapped bool
|
||||
|
||||
if currNodeChildrenMap, isCurrNodeMapped = childrenMapsByNode[curr]; !isCurrNodeMapped {
|
||||
currNodeChildrenMap = make(map[string]*Node[models.File])
|
||||
childrenMapsByNode[curr] = currNodeChildrenMap
|
||||
}
|
||||
|
||||
child, doesCurrNodeHaveChildAlready := currNodeChildrenMap[path]
|
||||
if doesCurrNodeHaveChildAlready {
|
||||
curr = child
|
||||
continue outer
|
||||
}
|
||||
|
||||
newChild := &Node[models.File]{
|
||||
@@ -36,6 +46,8 @@ func BuildTreeFromFiles(files []*models.File) *Node[models.File] {
|
||||
}
|
||||
curr.Children = append(curr.Children, newChild)
|
||||
|
||||
currNodeChildrenMap[path] = newChild
|
||||
|
||||
curr = newChild
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ const (
|
||||
DisplayAll FileTreeDisplayFilter = iota
|
||||
DisplayStaged
|
||||
DisplayUnstaged
|
||||
DisplayTracked
|
||||
// this shows files with merge conflicts
|
||||
DisplayConflicted
|
||||
)
|
||||
@@ -82,6 +83,8 @@ func (self *FileTree) getFilesForDisplay() []*models.File {
|
||||
return self.FilterFiles(func(file *models.File) bool { return file.HasStagedChanges })
|
||||
case DisplayUnstaged:
|
||||
return self.FilterFiles(func(file *models.File) bool { return file.HasUnstagedChanges })
|
||||
case DisplayTracked:
|
||||
return self.FilterFiles(func(file *models.File) bool { return file.Tracked })
|
||||
case DisplayConflicted:
|
||||
return self.FilterFiles(func(file *models.File) bool { return file.HasMergeConflicts })
|
||||
default:
|
||||
|
||||
@@ -40,6 +40,19 @@ func TestFilterAction(t *testing.T) {
|
||||
{Name: "file1", ShortStatus: "M ", HasStagedChanges: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter files that are tracked",
|
||||
filter: DisplayTracked,
|
||||
files: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Name: "dir2/file5", ShortStatus: "M ", Tracked: false},
|
||||
{Name: "file1", ShortStatus: "M ", Tracked: true},
|
||||
},
|
||||
expected: []*models.File{
|
||||
{Name: "dir2/dir2/file4", ShortStatus: "M ", Tracked: true},
|
||||
{Name: "file1", ShortStatus: "M ", Tracked: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "filter all files",
|
||||
filter: DisplayAll,
|
||||
|
||||
@@ -29,8 +29,8 @@ func (self *guiCommon) Refresh(opts types.RefreshOptions) error {
|
||||
return self.gui.helpers.Refresh.Refresh(opts)
|
||||
}
|
||||
|
||||
func (self *guiCommon) PostRefreshUpdate(context types.Context) error {
|
||||
return self.gui.postRefreshUpdate(context)
|
||||
func (self *guiCommon) PostRefreshUpdate(context types.Context) {
|
||||
self.gui.postRefreshUpdate(context)
|
||||
}
|
||||
|
||||
func (self *guiCommon) RunSubprocessAndRefresh(cmdObj oscommands.ICmdObj) error {
|
||||
|
||||
@@ -57,6 +57,11 @@ func (self *GuiDriver) Click(x, y int) {
|
||||
0,
|
||||
)
|
||||
self.waitTillIdle()
|
||||
self.gui.g.ReplayedEvents.MouseEvents <- gocui.NewTcellMouseEventWrapper(
|
||||
tcell.NewEventMouse(x, y, tcell.ButtonNone, 0),
|
||||
0,
|
||||
)
|
||||
self.waitTillIdle()
|
||||
}
|
||||
|
||||
// wait until lazygit is idle (i.e. all processing is done) before continuing
|
||||
|
||||
@@ -57,7 +57,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = gui.c.PostRefreshUpdate(gui.State.Contexts.Menu)
|
||||
gui.c.PostRefreshUpdate(gui.State.Contexts.Menu)
|
||||
|
||||
// TODO: ensure that if we're opened a menu from within a menu that it renders correctly
|
||||
gui.c.Context().Push(gui.State.Contexts.Menu)
|
||||
|
||||
@@ -9,8 +9,13 @@ import (
|
||||
type CherryPicking struct {
|
||||
CherryPickedCommits []*models.Commit
|
||||
|
||||
// we only allow cherry picking from one context at a time, so you can't copy a commit from the local commits context and then also copy a commit in the reflog context
|
||||
// we only allow cherry picking from one context at a time, so you can't copy a commit from
|
||||
// the local commits context and then also copy a commit in the reflog context
|
||||
ContextKey string
|
||||
|
||||
// keep track of whether the currently copied commits have been pasted already. If so, we hide
|
||||
// the mode and the blue display of the commits, but we still allow pasting them again.
|
||||
DidPaste bool
|
||||
}
|
||||
|
||||
func New() *CherryPicking {
|
||||
@@ -21,10 +26,18 @@ func New() *CherryPicking {
|
||||
}
|
||||
|
||||
func (self *CherryPicking) Active() bool {
|
||||
return self.CanPaste() && !self.DidPaste
|
||||
}
|
||||
|
||||
func (self *CherryPicking) CanPaste() bool {
|
||||
return len(self.CherryPickedCommits) > 0
|
||||
}
|
||||
|
||||
func (self *CherryPicking) SelectedHashSet() *set.Set[string] {
|
||||
if self.DidPaste {
|
||||
return set.New[string]()
|
||||
}
|
||||
|
||||
hashes := lo.Map(self.CherryPickedCommits, func(commit *models.Commit, _ int) string {
|
||||
return commit.Hash
|
||||
})
|
||||
|
||||
@@ -94,7 +94,7 @@ func (s *State) ToggleStickySelectRange() {
|
||||
}
|
||||
|
||||
func (s *State) ToggleSelectRange(sticky bool) {
|
||||
if s.selectMode == RANGE {
|
||||
if s.SelectingRange() {
|
||||
s.selectMode = LINE
|
||||
} else {
|
||||
s.selectMode = RANGE
|
||||
@@ -249,7 +249,7 @@ func (s *State) AdjustSelectedLineIdx(change int) {
|
||||
s.SelectLine(s.selectedLineIdx + change)
|
||||
}
|
||||
|
||||
func (s *State) RenderForLineIndices(isFocused bool, includedLineIndices []int) string {
|
||||
func (s *State) RenderForLineIndices(includedLineIndices []int) string {
|
||||
includedLineIndicesSet := set.NewFromSlice(includedLineIndices)
|
||||
return s.patch.FormatView(patch.FormatViewOpts{
|
||||
IncLineIndices: includedLineIndicesSet,
|
||||
|
||||
@@ -107,6 +107,7 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) {
|
||||
func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
||||
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||
Title: opts.Title,
|
||||
Multiline: opts.Multiline,
|
||||
Prompt: opts.InitialContent,
|
||||
Editable: true,
|
||||
HandleConfirmPrompt: opts.HandleConfirm,
|
||||
|
||||
@@ -21,7 +21,7 @@ var nameIconMap = map[string]IconProperties{
|
||||
".bash_profile": {Icon: "\ue615", Color: 113}, //
|
||||
".bashprofile": {Icon: "\ue615", Color: 113}, //
|
||||
".bashrc": {Icon: "\ue795", Color: 113}, //
|
||||
".dockerignore": {Icon: "\uf0868", Color: 68}, //
|
||||
".dockerignore": {Icon: "\U000f0868", Color: 68}, //
|
||||
".ds_store": {Icon: "\ue615", Color: 239}, //
|
||||
".editorconfig": {Icon: "\ue652", Color: 255}, //
|
||||
".env": {Icon: "\uf462", Color: 227}, //
|
||||
@@ -44,7 +44,7 @@ var nameIconMap = map[string]IconProperties{
|
||||
".mailmap": {Icon: "\U000f02a2", Color: 202}, //
|
||||
".npmignore": {Icon: "\ue71e", Color: 197}, //
|
||||
".npmrc": {Icon: "\ue71e", Color: 197}, //
|
||||
".nuxtrc": {Icon: "\uf1106", Color: 42}, //
|
||||
".nuxtrc": {Icon: "\U000f1106", Color: 42}, //
|
||||
".nvmrc": {Icon: "\ue718", Color: 71}, //
|
||||
".prettierignore": {Icon: "\ue6b4", Color: 33}, //
|
||||
".prettierrc": {Icon: "\ue6b4", Color: 33}, //
|
||||
@@ -76,21 +76,21 @@ var nameIconMap = map[string]IconProperties{
|
||||
"cantorrc": {Icon: "\uf373", Color: 32}, //
|
||||
"Cargo.lock": {Icon: "\ue7a8", Color: 216}, //
|
||||
"Cargo.toml": {Icon: "\ue7a8", Color: 216}, //
|
||||
"checkhealth": {Icon: "\uf04d9", Color: 75}, //
|
||||
"checkhealth": {Icon: "\U000f04d9", Color: 75}, //
|
||||
"cmakelists.txt": {Icon: "\ue615", Color: 66}, //
|
||||
"commit_editmsg": {Icon: "\ue702", Color: 196}, //
|
||||
"COMMIT_EDITMSG": {Icon: "\ue702", Color: 239}, //
|
||||
"commitlint.config.js": {Icon: "\uf0718", Color: 30}, //
|
||||
"commitlint.config.ts": {Icon: "\uf0718", Color: 30}, //
|
||||
"commitlint.config.js": {Icon: "\U000f0718", Color: 30}, //
|
||||
"commitlint.config.ts": {Icon: "\U000f0718", Color: 30}, //
|
||||
"compose.yaml": {Icon: "\uf308", Color: 68}, //
|
||||
"compose.yml": {Icon: "\uf308", Color: 68}, //
|
||||
"config": {Icon: "\ue5fc", Color: 241}, //
|
||||
"containerfile": {Icon: "\uf0868", Color: 68}, //
|
||||
"containerfile": {Icon: "\U000f0868", Color: 68}, //
|
||||
"copying": {Icon: "\ue60a", Color: 185}, //
|
||||
"copying.lesser": {Icon: "\ue60a", Color: 185}, //
|
||||
"docker-compose.yaml": {Icon: "\uf308", Color: 68}, //
|
||||
"docker-compose.yml": {Icon: "\uf308", Color: 68}, //
|
||||
"dockerfile": {Icon: "\uf0868", Color: 68}, //
|
||||
"dockerfile": {Icon: "\U000f0868", Color: 68}, //
|
||||
"Dockerfile": {Icon: "\uf308", Color: 68}, //
|
||||
"ds_store": {Icon: "\uf179", Color: 15}, //
|
||||
"eslint.config.cjs": {Icon: "\ue655", Color: 56}, //
|
||||
@@ -148,10 +148,10 @@ var nameIconMap = map[string]IconProperties{
|
||||
"mpv.conf": {Icon: "\uf36e", Color: 53}, //
|
||||
"node_modules": {Icon: "\ue718", Color: 197}, //
|
||||
"npmignore": {Icon: "\ue71e", Color: 197}, //
|
||||
"nuxt.config.cjs": {Icon: "\uf1106", Color: 42}, //
|
||||
"nuxt.config.js": {Icon: "\uf1106", Color: 42}, //
|
||||
"nuxt.config.mjs": {Icon: "\uf1106", Color: 42}, //
|
||||
"nuxt.config.ts": {Icon: "\uf1106", Color: 42}, //
|
||||
"nuxt.config.cjs": {Icon: "\U000f1106", Color: 42}, //
|
||||
"nuxt.config.js": {Icon: "\U000f1106", Color: 42}, //
|
||||
"nuxt.config.mjs": {Icon: "\U000f1106", Color: 42}, //
|
||||
"nuxt.config.ts": {Icon: "\U000f1106", Color: 42}, //
|
||||
"package.json": {Icon: "\ue71e", Color: 197}, //
|
||||
"package-lock.json": {Icon: "\ue71e", Color: 52}, //
|
||||
"PKGBUILD": {Icon: "\uf303", Color: 38}, //
|
||||
@@ -165,23 +165,23 @@ var nameIconMap = map[string]IconProperties{
|
||||
"PrusaSlicer.ini": {Icon: "\uf351", Color: 202}, //
|
||||
"py.typed": {Icon: "\ue606", Color: 214}, //
|
||||
"QtProject.conf": {Icon: "\uf375", Color: 77}, //
|
||||
"R": {Icon: "\uf07d4", Color: 25}, //
|
||||
"robots.txt": {Icon: "\uf06a9", Color: 60}, //
|
||||
"R": {Icon: "\U000f07d4", Color: 25}, //
|
||||
"robots.txt": {Icon: "\U000f06a9", Color: 60}, //
|
||||
"rubydoc": {Icon: "\ue73b", Color: 160}, //
|
||||
"settings.gradle": {Icon: "\ue660", Color: 24}, //
|
||||
"svelte.config.js": {Icon: "\ue697", Color: 196}, //
|
||||
"sxhkdrc": {Icon: "\uf355", Color: 236}, //
|
||||
"sym-lib-table": {Icon: "\uf34c", Color: 231}, //
|
||||
"tailwind.config.js": {Icon: "\uf13ff", Color: 45}, //
|
||||
"tailwind.config.mjs": {Icon: "\uf13ff", Color: 45}, //
|
||||
"tailwind.config.ts": {Icon: "\uf13ff", Color: 45}, //
|
||||
"tailwind.config.js": {Icon: "\U000f13ff", Color: 45}, //
|
||||
"tailwind.config.mjs": {Icon: "\U000f13ff", Color: 45}, //
|
||||
"tailwind.config.ts": {Icon: "\U000f13ff", Color: 45}, //
|
||||
"tmux.conf": {Icon: "\uebc8", Color: 34}, //
|
||||
"tmux.conf.local": {Icon: "\uebc8", Color: 34}, //
|
||||
"tsconfig.json": {Icon: "\ue69d", Color: 74}, //
|
||||
"unlicense": {Icon: "\ue60a", Color: 185}, //
|
||||
"vagrantfile$": {Icon: "\uf2b8", Color: 27}, //
|
||||
"vlcrc": {Icon: "\uf057c", Color: 208}, //
|
||||
"webpack": {Icon: "\uf072b", Color: 74}, //
|
||||
"vlcrc": {Icon: "\U000f057c", Color: 208}, //
|
||||
"webpack": {Icon: "\U000f072b", Color: 74}, //
|
||||
"weston.ini": {Icon: "\uf367", Color: 214}, //
|
||||
"workspace": {Icon: "\ue63a", Color: 113}, //
|
||||
"xmobarrc.hs": {Icon: "\uf35e", Color: 203}, //
|
||||
@@ -207,7 +207,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".app": {Icon: "\ueae8", Color: 124}, //
|
||||
".apple": {Icon: "\uf179", Color: 15}, //
|
||||
".applescript": {Icon: "\uf179", Color: 66}, //
|
||||
".asc": {Icon: "\uf099d", Color: 242}, //
|
||||
".asc": {Icon: "\U000f099d", Color: 242}, //
|
||||
".ass": {Icon: "\U000f0a16", Color: 214}, //
|
||||
".astro": {Icon: "\ue6b3", Color: 197}, //
|
||||
".avif": {Icon: "\uf1c5", Color: 140}, //
|
||||
@@ -320,7 +320,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".exe": {Icon: "\uf17a", Color: 81}, //
|
||||
".ex": {Icon: "\ue62d", Color: 140}, //
|
||||
".exs": {Icon: "\ue62d", Color: 140}, //
|
||||
".f3d": {Icon: "\uf0eeb", Color: 101}, //
|
||||
".f3d": {Icon: "\U000f0eeb", Color: 101}, //
|
||||
".f90": {Icon: "\U000f121a", Color: 97}, //
|
||||
".fbx": {Icon: "\U000f01a7", Color: 102}, //
|
||||
".fcbak": {Icon: "\uf336", Color: 160}, //
|
||||
@@ -380,7 +380,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".hs": {Icon: "\ue777", Color: 140}, //
|
||||
".htm": {Icon: "\uf13b", Color: 196}, //
|
||||
".html": {Icon: "\uf13b", Color: 196}, //
|
||||
".huff": {Icon: "\uf0858", Color: 56}, //
|
||||
".huff": {Icon: "\U000f0858", Color: 56}, //
|
||||
".hurl": {Icon: "\uf0ec", Color: 198}, //
|
||||
".hx": {Icon: "\ue666", Color: 208}, //
|
||||
".hxx": {Icon: "\uf0fd", Color: 140}, //
|
||||
@@ -425,7 +425,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".jsx": {Icon: "\ue7ba", Color: 45}, //
|
||||
".jwmrc": {Icon: "\uf35b", Color: 32}, //
|
||||
".jxl": {Icon: "\uf1c5", Color: 241}, //
|
||||
".kbx": {Icon: "\uf0bc4", Color: 243}, //
|
||||
".kbx": {Icon: "\U000f0bc4", Color: 243}, //
|
||||
".kdb": {Icon: "\uf23e", Color: 71}, //
|
||||
".kdbx": {Icon: "\uf23e", Color: 71}, //
|
||||
".kdenlive": {Icon: "\uf33c", Color: 110}, //
|
||||
@@ -472,12 +472,12 @@ var extIconMap = map[string]IconProperties{
|
||||
".magnet": {Icon: "\uf076", Color: 124}, //
|
||||
".makefile": {Icon: "\ue779", Color: 66}, //
|
||||
".markdown": {Icon: "\uf48a", Color: 74}, //
|
||||
".material": {Icon: "\uf0509", Color: 163}, //
|
||||
".md5": {Icon: "\uf0565", Color: 103}, //
|
||||
".material": {Icon: "\U000f0509", Color: 163}, //
|
||||
".md5": {Icon: "\U000f0565", Color: 103}, //
|
||||
".md": {Icon: "\uf48a", Color: 74}, //
|
||||
".mdx": {Icon: "\uf48a", Color: 74}, //
|
||||
".m": {Icon: "\ue61e", Color: 111}, //
|
||||
".mint": {Icon: "\uf032a", Color: 108}, //
|
||||
".mint": {Icon: "\U000f032a", Color: 108}, //
|
||||
".mjs": {Icon: "\ue74e", Color: 185}, //
|
||||
".mkd": {Icon: "\uf48a", Color: 74}, //
|
||||
".mk": {Icon: "\ue795", Color: 241}, //
|
||||
@@ -535,10 +535,10 @@ var extIconMap = map[string]IconProperties{
|
||||
".properties": {Icon: "\ue60b", Color: 185}, //
|
||||
".ps1": {Icon: "\ue795", Color: 241}, //
|
||||
".psb": {Icon: "\ue7b8", Color: 74}, //
|
||||
".psd1": {Icon: "\uf0a0a", Color: 68}, //
|
||||
".psd1": {Icon: "\U000f0a0a", Color: 68}, //
|
||||
".psd": {Icon: "\ue7b8", Color: 241}, //
|
||||
".psm1": {Icon: "\uf0a0a", Color: 68}, //
|
||||
".pub": {Icon: "\uf0dd6", Color: 222}, //
|
||||
".psm1": {Icon: "\U000f0a0a", Color: 68}, //
|
||||
".pub": {Icon: "\U000f0dd6", Color: 222}, //
|
||||
".pxd": {Icon: "\ue606", Color: 39}, //
|
||||
".pxi": {Icon: "\ue606", Color: 39}, //
|
||||
".pxm": {Icon: "\uf1c5", Color: 241}, //
|
||||
@@ -570,7 +570,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".rlib": {Icon: "\ue7a8", Color: 216}, //
|
||||
".rmd": {Icon: "\uf48a", Color: 74}, //
|
||||
".rpm": {Icon: "\ue7bb", Color: 52}, //
|
||||
".rproj": {Icon: "\uf05c6", Color: 29}, //
|
||||
".rproj": {Icon: "\U000f05c6", Color: 29}, //
|
||||
".rs": {Icon: "\ue7a8", Color: 216}, //
|
||||
".rspec": {Icon: "\ue21e", Color: 160}, //
|
||||
".rspec_parallel": {Icon: "\ue21e", Color: 160}, //
|
||||
@@ -584,13 +584,13 @@ var extIconMap = map[string]IconProperties{
|
||||
".scad": {Icon: "\uf34e", Color: 220}, //
|
||||
".scala": {Icon: "\ue737", Color: 74}, //
|
||||
".sc": {Icon: "\ue737", Color: 167}, //
|
||||
".scm": {Icon: "\uf0627", Color: 255}, //
|
||||
".scm": {Icon: "\U000f0627", Color: 255}, //
|
||||
".scss": {Icon: "\ue749", Color: 204}, //
|
||||
".sha1": {Icon: "\uf0565", Color: 103}, //
|
||||
".sha224": {Icon: "\uf0565", Color: 103}, //
|
||||
".sha256": {Icon: "\uf0565", Color: 103}, //
|
||||
".sha384": {Icon: "\uf0565", Color: 103}, //
|
||||
".sha512": {Icon: "\uf0565", Color: 103}, //
|
||||
".sha1": {Icon: "\U000f0565", Color: 103}, //
|
||||
".sha224": {Icon: "\U000f0565", Color: 103}, //
|
||||
".sha256": {Icon: "\U000f0565", Color: 103}, //
|
||||
".sha384": {Icon: "\U000f0565", Color: 103}, //
|
||||
".sha512": {Icon: "\U000f0565", Color: 103}, //
|
||||
".shell": {Icon: "\ue795", Color: 239}, //
|
||||
".sh": {Icon: "\ue795", Color: 239}, //
|
||||
".sig": {Icon: "\u03bb", Color: 166}, // λ
|
||||
@@ -631,10 +631,10 @@ var extIconMap = map[string]IconProperties{
|
||||
".swift": {Icon: "\ue755", Color: 208}, //
|
||||
".tar": {Icon: "\uf410", Color: 241}, //
|
||||
".taz": {Icon: "\uf410", Color: 241}, //
|
||||
".tbc": {Icon: "\uf06d3", Color: 25}, //
|
||||
".tbc": {Icon: "\U000f06d3", Color: 25}, //
|
||||
".tbz2": {Icon: "\uf410", Color: 241}, //
|
||||
".tbz": {Icon: "\uf410", Color: 241}, //
|
||||
".tcl": {Icon: "\uf06d3", Color: 25}, //
|
||||
".tcl": {Icon: "\U000f06d3", Color: 25}, //
|
||||
".templ": {Icon: "\ueac4", Color: 178}, //
|
||||
".terminal": {Icon: "\uf489", Color: 34}, //
|
||||
".test.js": {Icon: "\uf499", Color: 185}, //
|
||||
@@ -680,7 +680,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".wav": {Icon: "\uf001", Color: 241}, //
|
||||
".webmanifest": {Icon: "\ue60b", Color: 185}, //
|
||||
".webm": {Icon: "\uf03d", Color: 241}, //
|
||||
".webpack": {Icon: "\uf072b", Color: 74}, //
|
||||
".webpack": {Icon: "\U000f072b", Color: 74}, //
|
||||
".webp": {Icon: "\uf1c5", Color: 241}, //
|
||||
".windows": {Icon: "\uf17a", Color: 81}, //
|
||||
".wma": {Icon: "\uf001", Color: 39}, //
|
||||
@@ -690,7 +690,7 @@ var extIconMap = map[string]IconProperties{
|
||||
".wrz": {Icon: "\U000f01a7", Color: 102}, //
|
||||
".wvc": {Icon: "\uf001", Color: 39}, //
|
||||
".wv": {Icon: "\uf001", Color: 39}, //
|
||||
".xaml": {Icon: "\uf0673", Color: 56}, //
|
||||
".xaml": {Icon: "\U000f0673", Color: 56}, //
|
||||
".xcf": {Icon: "\uf338", Color: 240}, //
|
||||
".xcplayground": {Icon: "\ue755", Color: 166}, //
|
||||
".xcstrings": {Icon: "\U000f05ca", Color: 31}, //
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package icons
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFileIcons(t *testing.T) {
|
||||
t.Run("TestFileIcons", func(t *testing.T) {
|
||||
for name, icon := range nameIconMap {
|
||||
if len([]rune(icon.Icon)) != 1 {
|
||||
t.Errorf("nameIconMap[\"%s\"] is not a single rune", name)
|
||||
}
|
||||
}
|
||||
|
||||
for ext, icon := range extIconMap {
|
||||
if len([]rune(icon.Icon)) != 1 {
|
||||
t.Errorf("extIconMap[\"%s\"] is not a single rune", ext)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -79,6 +79,14 @@ func (self *HandlerCreator) call(customCommand config.CustomCommand) func() erro
|
||||
}
|
||||
return self.inputPrompt(resolvedPrompt, wrappedF)
|
||||
}
|
||||
case "textbox":
|
||||
f = func() error {
|
||||
resolvedPrompt, err := self.resolver.resolvePrompt(&prompt, resolveTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.textboxPrompt(resolvedPrompt, wrappedF)
|
||||
}
|
||||
case "menu":
|
||||
f = func() error {
|
||||
resolvedPrompt, err := self.resolver.resolvePrompt(&prompt, resolveTemplate)
|
||||
@@ -130,6 +138,19 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *HandlerCreator) textboxPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: prompt.Title,
|
||||
InitialContent: prompt.InitialValue,
|
||||
Multiline: true,
|
||||
HandleConfirm: func(str string) error {
|
||||
return wrappedF(str)
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *HandlerCreator) generateFindSuggestionsFunc(prompt *config.CustomCommandPrompt) (func(string) []*types.Suggestion, error) {
|
||||
if prompt.Suggestions.Preset != "" && prompt.Suggestions.Command != "" {
|
||||
return nil, fmt.Errorf(
|
||||
|
||||
@@ -53,9 +53,7 @@ func (gui *Gui) newStringTaskWithoutScroll(view *gocui.View, str string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Using empty key so that on subsequent calls we won't reset the view's origin.
|
||||
// Note this means that we will be scrolling back to the top if we're switching from a different key
|
||||
if err := manager.NewTask(f, ""); err != nil {
|
||||
if err := manager.NewTask(f, manager.GetTaskKey()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -71,7 +69,7 @@ func (gui *Gui) newStringTaskWithScroll(view *gocui.View, str string, originX in
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := manager.NewTask(f, ""); err != nil {
|
||||
if err := manager.NewTask(f, manager.GetTaskKey()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ type IGuiCommon interface {
|
||||
// we call this when we've changed something in the view model but not the actual model,
|
||||
// e.g. expanding or collapsing a folder in a file view. Calling 'Refresh' in this
|
||||
// case would be overkill, although refresh will internally call 'PostRefreshUpdate'
|
||||
PostRefreshUpdate(Context) error
|
||||
PostRefreshUpdate(Context)
|
||||
|
||||
// renders string to a view without resetting its origin
|
||||
SetViewContent(view *gocui.View, content string)
|
||||
@@ -153,6 +153,7 @@ type CreatePopupPanelOpts struct {
|
||||
HasLoader bool
|
||||
Editable bool
|
||||
Title string
|
||||
Multiline bool
|
||||
Prompt string
|
||||
HandleConfirm func() error
|
||||
HandleConfirmPrompt func(string) error
|
||||
@@ -166,6 +167,7 @@ type CreatePopupPanelOpts struct {
|
||||
|
||||
type ConfirmOpts struct {
|
||||
Title string
|
||||
Multiline bool
|
||||
Prompt string
|
||||
HandleConfirm func() error
|
||||
HandleClose func() error
|
||||
@@ -176,6 +178,7 @@ type ConfirmOpts struct {
|
||||
|
||||
type PromptOpts struct {
|
||||
Title string
|
||||
Multiline bool
|
||||
InitialContent string
|
||||
FindSuggestionsFunc func(string) []*Suggestion
|
||||
HandleConfirm func(string) error
|
||||
|
||||
@@ -177,11 +177,11 @@ type IPatchExplorerContext interface {
|
||||
GetState() *patch_exploring.State
|
||||
SetState(*patch_exploring.State)
|
||||
GetIncludedLineIndices() []int
|
||||
RenderAndFocus(isFocused bool)
|
||||
Render(isFocused bool)
|
||||
RenderAndFocus()
|
||||
Render()
|
||||
Focus()
|
||||
GetContentToRender(isFocused bool) string
|
||||
NavigateTo(isFocused bool, selectedLineIdx int)
|
||||
GetContentToRender() string
|
||||
NavigateTo(selectedLineIdx int)
|
||||
GetMutex() *deadlock.Mutex
|
||||
IsPatchExplorerContext() // used for type switch
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (gui *Gui) render() {
|
||||
// postRefreshUpdate is to be called on a context after the state that it depends on has been refreshed
|
||||
// if the context's view is set to another context we do nothing.
|
||||
// if the context's view is the current view we trigger a focus; re-selecting the current item.
|
||||
func (gui *Gui) postRefreshUpdate(c types.Context) error {
|
||||
func (gui *Gui) postRefreshUpdate(c types.Context) {
|
||||
t := time.Now()
|
||||
defer func() {
|
||||
gui.Log.Infof("postRefreshUpdate for %s took %s", c.GetKey(), time.Since(t))
|
||||
@@ -137,6 +137,4 @@ func (gui *Gui) postRefreshUpdate(c types.Context) error {
|
||||
if gui.currentViewName() == c.GetViewName() {
|
||||
c.HandleFocus(types.OnFocusOpts{})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ func (gui *Gui) createAllViews() error {
|
||||
view.Wrap = true
|
||||
view.IgnoreCarriageReturns = true
|
||||
view.UnderlineHyperLinksOnlyOnHover = true
|
||||
view.AutoRenderHyperLinks = true
|
||||
}
|
||||
|
||||
gui.Views.Staging.Title = gui.c.Tr.UnstagedChanges
|
||||
@@ -157,6 +158,7 @@ func (gui *Gui) createAllViews() error {
|
||||
|
||||
gui.Views.Confirmation.Visible = false
|
||||
gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor)
|
||||
gui.Views.Confirmation.AutoRenderHyperLinks = true
|
||||
|
||||
gui.Views.Suggestions.Visible = false
|
||||
|
||||
@@ -171,6 +173,7 @@ func (gui *Gui) createAllViews() error {
|
||||
gui.Views.Extras.Title = gui.c.Tr.CommandLog
|
||||
gui.Views.Extras.Autoscroll = true
|
||||
gui.Views.Extras.Wrap = true
|
||||
gui.Views.Extras.AutoRenderHyperLinks = true
|
||||
|
||||
gui.Views.Snake.Title = gui.c.Tr.SnakeTitle
|
||||
gui.Views.Snake.FgColor = gocui.ColorGreen
|
||||
|
||||
+10
-6
@@ -87,6 +87,7 @@ type TranslationSet struct {
|
||||
AllFilesDiffCopiedToast string
|
||||
FilterStagedFiles string
|
||||
FilterUnstagedFiles string
|
||||
FilterTrackedFiles string
|
||||
ResetFilter string
|
||||
MergeConflictsTitle string
|
||||
Checkout string
|
||||
@@ -107,6 +108,7 @@ type TranslationSet struct {
|
||||
DeleteLocalBranch string
|
||||
DeleteRemoteBranchOption string
|
||||
DeleteRemoteBranchPrompt string
|
||||
DeleteLocalAndRemoteBranchPrompt string
|
||||
ForceDeleteBranchTitle string
|
||||
ForceDeleteBranchMessage string
|
||||
RebaseBranch string
|
||||
@@ -472,8 +474,8 @@ type TranslationSet struct {
|
||||
RemoveRemoteTooltip string
|
||||
RemoveRemotePrompt string
|
||||
DeleteRemoteBranch string
|
||||
DeleteRemoteBranchMessage string
|
||||
DeleteRemoteBranchTooltip string
|
||||
DeleteLocalAndRemoteBranch string
|
||||
SetAsUpstream string
|
||||
SetAsUpstreamTooltip string
|
||||
SetUpstream string
|
||||
@@ -553,6 +555,7 @@ type TranslationSet struct {
|
||||
MustStashWarning string
|
||||
MustStashTitle string
|
||||
ConfirmationTitle string
|
||||
PressToSubmit string
|
||||
PrevPage string
|
||||
NextPage string
|
||||
GotoTop string
|
||||
@@ -849,7 +852,6 @@ type Actions struct {
|
||||
CheckoutBranch string
|
||||
ForceCheckoutBranch string
|
||||
DeleteLocalBranch string
|
||||
DeleteBranch string
|
||||
Merge string
|
||||
SquashMerge string
|
||||
RebaseBranch string
|
||||
@@ -1075,6 +1077,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
AllFilesDiffCopiedToast: "All files diff copied to clipboard",
|
||||
FilterStagedFiles: "Show only staged files",
|
||||
FilterUnstagedFiles: "Show only unstaged files",
|
||||
FilterTrackedFiles: "Show only tracked files",
|
||||
ResetFilter: "Reset filter",
|
||||
NoChangedFiles: "No changed files",
|
||||
SoftReset: "Soft reset",
|
||||
@@ -1088,6 +1091,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
DeleteLocalBranch: "Delete local branch",
|
||||
DeleteRemoteBranchOption: "Delete remote branch",
|
||||
DeleteRemoteBranchPrompt: "Are you sure you want to delete the remote branch '{{.selectedBranchName}}' from '{{.upstream}}'?",
|
||||
DeleteLocalAndRemoteBranchPrompt: "Are you sure you want to delete both '{{.localBranchName}}' from your machine, and '{{.remoteBranchName}}' from '{{.remoteName}}'?",
|
||||
ForceDeleteBranchTitle: "Force delete branch",
|
||||
ForceDeleteBranchMessage: "'{{.selectedBranchName}}' is not fully merged. Are you sure you want to delete it?",
|
||||
RebaseBranch: "Rebase",
|
||||
@@ -1461,10 +1465,10 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
EditRemoteUrl: `Enter updated remote url for {{.remoteName}}:`,
|
||||
RemoveRemote: `Remove remote`,
|
||||
RemoveRemoteTooltip: `Remove the selected remote. Any local branches tracking a remote branch from the remote will be unaffected.`,
|
||||
RemoveRemotePrompt: "Are you sure you want to remove remote",
|
||||
RemoveRemotePrompt: "Are you sure you want to remove remote?",
|
||||
DeleteRemoteBranch: "Delete remote branch",
|
||||
DeleteRemoteBranchMessage: "Are you sure you want to delete remote branch",
|
||||
DeleteRemoteBranchTooltip: "Delete the remote branch from the remote.",
|
||||
DeleteLocalAndRemoteBranch: "Delete local and remote branch",
|
||||
SetAsUpstream: "Set as upstream",
|
||||
SetAsUpstreamTooltip: "Set the selected remote branch as the upstream of the checked-out branch.",
|
||||
SetUpstream: "Set upstream of selected branch",
|
||||
@@ -1480,7 +1484,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
ViewUpstreamRebaseOptionsTooltip: "View options for rebasing the checked-out branch onto {{upstream}}. Note: this will not rebase the selected branch onto the upstream, it will rebase the checked-out branch onto the upstream.",
|
||||
UpstreamGenericName: "upstream of selected branch",
|
||||
SetUpstreamTitle: "Set upstream branch",
|
||||
SetUpstreamMessage: "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'",
|
||||
SetUpstreamMessage: "Are you sure you want to set the upstream branch of '{{.checkedOut}}' to '{{.selected}}'?",
|
||||
EditRemoteTooltip: "Edit the selected remote's name or URL.",
|
||||
TagCommit: "Tag commit",
|
||||
TagCommitTooltip: "Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description.",
|
||||
@@ -1542,6 +1546,7 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
MustStashWarning: "Pulling a patch out into the index requires stashing and unstashing your changes. If something goes wrong, you'll be able to access your files from the stash. Continue?",
|
||||
MustStashTitle: "Must stash",
|
||||
ConfirmationTitle: "Confirmation panel",
|
||||
PressToSubmit: "Press {{.Key}} to submit",
|
||||
PrevPage: "Previous page",
|
||||
NextPage: "Next page",
|
||||
GotoTop: "Scroll to top",
|
||||
@@ -1797,7 +1802,6 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
CheckoutBranch: "Checkout branch",
|
||||
ForceCheckoutBranch: "Force checkout branch",
|
||||
DeleteLocalBranch: "Delete local branch",
|
||||
DeleteBranch: "Delete branch",
|
||||
Merge: "Merge",
|
||||
SquashMerge: "Squash merge",
|
||||
RebaseBranch: "Rebase branch",
|
||||
|
||||
@@ -5,79 +5,176 @@
|
||||
"BranchesTitle": "分支",
|
||||
"CommitsTitle": "提交",
|
||||
"StashTitle": "贮藏",
|
||||
"UnstagedChanges": "未暂存更改",
|
||||
"StagedChanges": "已暂存更改",
|
||||
"SnakeTitle": "贪吃蛇",
|
||||
"EasterEgg": "彩蛋",
|
||||
"UnstagedChanges": "未暂存变更",
|
||||
"StagedChanges": "已暂存变更",
|
||||
"MainTitle": "主要",
|
||||
"StagingTitle": "正在暂存",
|
||||
"MergingTitle": "正在合并",
|
||||
"SquashMergeUncommittedTitle": "压缩合并并保持未提交状态",
|
||||
"SquashMergeCommittedTitle": "压缩合并,然后提交",
|
||||
"SquashMergeUncommitted": "将分支 ‘{{.selectedBranch}}’ 压缩合并到工作树中",
|
||||
"SquashMergeCommitted": "将分支 '{{.selectedBranch}}' 压缩合并为单个提交,到 '{{.checkedOutBranch}}' 分支中。",
|
||||
"RegularMergeTooltip": "将分支 '{{.selectedBranch}}' 合并到 '{{.checkedOutBranch}}'",
|
||||
"NormalTitle": "正常",
|
||||
"LogTitle": "日志",
|
||||
"CommitSummary": "提交信息",
|
||||
"CredentialsUsername": "用户名",
|
||||
"CredentialsPassword": "密码",
|
||||
"CredentialsPassphrase": "输入 SSH 密钥的密码",
|
||||
"CredentialsPIN": "为 SSH key 输入PIN",
|
||||
"PassUnameWrong": "密码 和/或 用户名错误",
|
||||
"Commit": "提交更改",
|
||||
"Commit": "提交变更",
|
||||
"CommitTooltip": "提交暂存文件",
|
||||
"AmendLastCommit": "修补最后一次提交",
|
||||
"AmendLastCommitTitle": "修补最后一次提交",
|
||||
"SureToAmend": "您确定要修补上一次提交吗?之后您可以从提交面板更改提交消息。",
|
||||
"NoCommitToAmend": "没有需要提交的修补。",
|
||||
"CommitChangesWithEditor": "提交更改(使用编辑器编辑提交信息)",
|
||||
"SureToAmend": "您确定要修补上一次提交吗?之后您可以从提交面板更改提交消息",
|
||||
"NoCommitToAmend": "没有需要提交的修补",
|
||||
"CommitChangesWithEditor": "提交变更(使用编辑器编辑提交信息)",
|
||||
"FindBaseCommitForFixup": "找到用于修复的基准提交",
|
||||
"FindBaseCommitForFixupTooltip": "找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md>",
|
||||
"NoBaseCommitsFound": "没有找到接触提交",
|
||||
"MultipleBaseCommitsFoundStaged": "找到了多个基础提交(尝试一次暂存更少的变更)",
|
||||
"MultipleBaseCommitsFoundUnstaged": "找到了多个基础提交(尝试暂存部分变更)",
|
||||
"BaseCommitIsAlreadyOnMainBranch": "此变更内容所在的提交已经存在于主分支上了",
|
||||
"BaseCommitIsNotInCurrentView": "基础提交不在当前视图中",
|
||||
"HunksWithOnlyAddedLinesWarning": "差异中仅包含添加行,小心检查这些是否属于已找到的主提交。\n\n是否继续?",
|
||||
"StatusTitle": "状态",
|
||||
"GlobalTitle": "全局键绑定",
|
||||
"Menu": "菜单",
|
||||
"Execute": "执行",
|
||||
"Stage": "切换暂存状态",
|
||||
"StageTooltip": "为选定的文件切换暂存状态",
|
||||
"ToggleStagedAll": "切换所有文件的暂存状态",
|
||||
"ToggleStagedAllTooltip": "切换工作区中所有文件的已暂存/未暂存状态",
|
||||
"ToggleTreeView": "切换文件树视图",
|
||||
"OpenMergeTool": "打开外部合并工具 (git mergetool)",
|
||||
"ToggleTreeViewTooltip": "在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。",
|
||||
"OpenDiffTool": "使用外部差异比较工具(git difftool)",
|
||||
"OpenMergeTool": "打开外部合并工具(git mergetool)",
|
||||
"OpenMergeToolTooltip": "执行 `git mergetool`.",
|
||||
"Refresh": "刷新",
|
||||
"RefreshTooltip": "刷新git状态(即在后台上运行`git status`,`git branch`等命令以更新面板内容) 不会运行`git fetch`",
|
||||
"Push": "推送",
|
||||
"Pull": "拉取",
|
||||
"PushTooltip": "推送当前分支到它的上游。如果上游为配置,你可以在弹窗中配置上游分支。",
|
||||
"PullTooltip": "从当前分支的远程分支获取改动。如果上游为配置,你可以在弹窗中配置上游分支。",
|
||||
"Scroll": "滚动",
|
||||
"FileFilter": "通过状态过滤文件",
|
||||
"CopyToClipboardMenu": "复制到剪贴板",
|
||||
"CopyFileName": "文件名",
|
||||
"CopyFilePath": "路径",
|
||||
"CopyFileDiffTooltip": "如果存在已暂存更改,该命令将仅作用于它们。否则将作用于所有未暂存更改。",
|
||||
"CopySelectedDiff": "比较选中的文件",
|
||||
"CopyAllFilesDiff": "对比全部文件",
|
||||
"NoContentToCopyError": "无可复制内容",
|
||||
"FileNameCopiedToast": "文件名已复制至剪贴板",
|
||||
"FilePathCopiedToast": "文件路径已复制至剪贴板",
|
||||
"FileDiffCopiedToast": "文件差异已复制至剪贴板",
|
||||
"AllFilesDiffCopiedToast": "全部文件差异已复制至剪贴板",
|
||||
"FilterStagedFiles": "仅显示已暂存文件",
|
||||
"FilterUnstagedFiles": "仅显示未暂存文件",
|
||||
"ResetFilter": "重置过滤",
|
||||
"MergeConflictsTitle": "合并冲突",
|
||||
"Checkout": "检出",
|
||||
"NoChangedFiles": "没有更改过文件",
|
||||
"CheckoutTooltip": "检出选中的项目",
|
||||
"CantCheckoutBranchWhilePulling": "当前分支在拉取远端时,无法检出到其他分支。",
|
||||
"TagCheckoutTooltip": "检出选择的标签作为分离的HEAD",
|
||||
"RemoteBranchCheckoutTooltip": "基于当前选中的远程分支检出一个新的本地分支,或者将远程分支作分离的HEAD。",
|
||||
"CantPullOrPushSameBranchTwice": "在推送或拉取分支的过程中,你不能再次推送或拉取同一个分支",
|
||||
"NoChangedFiles": "没有变更的文件",
|
||||
"SoftReset": "软重置",
|
||||
"AlreadyCheckedOutBranch": "您已经检出至此分支",
|
||||
"SureForceCheckout": "您确定要强制检出吗?您将丢失所有本地更改",
|
||||
"SureForceCheckout": "您确定要强制检出吗?您将丢失所有本地变更",
|
||||
"ForceCheckoutBranch": "强制检出分支",
|
||||
"BranchName": "分支名称",
|
||||
"NewBranchNameBranchOff": "新分支名称(基于 {{.branchName}})",
|
||||
"NewBranchNameBranchOff": "新分支名称(基于 {{.branchName}})",
|
||||
"CantDeleteCheckOutBranch": "您不能删除已检出的分支!",
|
||||
"DeleteBranchTitle": "删除分支'{{.selectedBranchName}}'?",
|
||||
"DeleteLocalBranch": "删除本地分支",
|
||||
"DeleteRemoteBranchOption": "删除远程分支",
|
||||
"DeleteRemoteBranchPrompt": "你确定要从'{{.upstream}}'中删除远程分支'{{.selectedBranchName}}'?",
|
||||
"ForceDeleteBranchTitle": "强制删除分支",
|
||||
"ForceDeleteBranchMessage": "{{.selectedBranchName}} 还没有被完全合并。您确定要删除它吗?",
|
||||
"RebaseBranch": "将已检出的分支变基到该分支",
|
||||
"RebaseBranchTooltip": "将检出的分支变基到所选的分支上。",
|
||||
"CantRebaseOntoSelf": "您不能将分支变基到其自身",
|
||||
"CantMergeBranchIntoItself": "您不能将分支合并到其自身",
|
||||
"ForceCheckout": "强制检出",
|
||||
"ForceCheckoutTooltip": "强制检出所选分支。这将在检出所选分支之前放弃工作目录中的所有本地更改。",
|
||||
"CheckoutByName": "按名称检出",
|
||||
"CheckoutByNameTooltip": "按名称检出。在输入框中,您可以输入'-' 来切换到最后一个分支。",
|
||||
"RemoteBranchCheckoutTitle": "检出 {{.branchName}}",
|
||||
"RemoteBranchCheckoutPrompt": "您希望已什么方式检出到该分支?",
|
||||
"CheckoutTypeNewBranch": "新建本地分支",
|
||||
"CheckoutTypeNewBranchTooltip": "检出远程分支到本地,并跟踪它。",
|
||||
"CheckoutTypeDetachedHead": "分离HEAD",
|
||||
"CheckoutTypeDetachedHeadTooltip": "将远程分支检出作为分离HEAD,如果您只想用来测试而不是正式使用,这会很有用。您之后仍可以根据它创建本地分支。",
|
||||
"NewBranch": "新分支",
|
||||
"NewBranchFromStashTooltip": "从选定的贮藏项创建一个新分支。这是通过 git 检查创建贮藏项的提交,从该提交创建一个新分支,然后将贮藏项作为附加提交应用到新分支来实现的。",
|
||||
"NoBranchesThisRepo": "此仓库中没有分支",
|
||||
"CommitWithoutMessageErr": "您必须编写提交消息才能进行提交",
|
||||
"Close": "关闭",
|
||||
"CloseCancel": "关闭",
|
||||
"Confirm": "确认",
|
||||
"Quit": "退出",
|
||||
"Fixup": "修正(fixup)",
|
||||
"SquashTooltip": "将已选提交压缩到该提交之下。这些选定的提交的消息会附加到该提交的消息之下。",
|
||||
"CannotSquashOrFixupFirstCommit": "下面没有可以压缩的提交",
|
||||
"Fixup": "修正(fixup)",
|
||||
"FixupTooltip": "将选定的提交合并到其下面的提交中。与压缩类似,但所选提交的消息将被丢弃。",
|
||||
"SureFixupThisCommit": "您确定要“修正”此提交吗?它将合并到下面的提交中",
|
||||
"SureSquashThisCommit": "您确定要将这个提交压缩到下面的提交中吗?",
|
||||
"Squash": "压缩",
|
||||
"PickCommitTooltip": "选择提交(变基过程中)",
|
||||
"Squash": "压缩(Squash)",
|
||||
"SquashMerge": "压缩合并",
|
||||
"PickCommitTooltip": "选择提交(变基过程中)",
|
||||
"Pick": "拣选(Pick)",
|
||||
"CantPickDisabledReason": "在变基期间,无法选择提交",
|
||||
"Edit": "编辑",
|
||||
"RevertCommit": "还原提交",
|
||||
"Revert": "撤销(Revert)",
|
||||
"RevertCommitTooltip": "为所选提交创建还原提交,这会反向应用所选提交的更改。",
|
||||
"Reword": "改写提交",
|
||||
"CommitRewordTooltip": "重写所选提交的消息。",
|
||||
"DropCommit": "删除提交",
|
||||
"DropCommitTooltip": "删除选中的提交。这将通过变基从分支中删除该提交,如果该提交修改的内容依赖于后续的提交,则需要解决合并冲突。",
|
||||
"MoveDownCommit": "下移提交",
|
||||
"MoveUpCommit": "上移提交",
|
||||
"CannotMoveAnyFurther": "无法进一步移动",
|
||||
"EditCommit": "编辑(开始交互式变基)",
|
||||
"EditCommitTooltip": "编辑提交",
|
||||
"AmendCommitTooltip": "用已暂存的更改来修补提交",
|
||||
"AmendCommitTooltip": "用已暂存的变更来修补提交",
|
||||
"Amend": "修补(Amend)",
|
||||
"ResetAuthor": "重置作者",
|
||||
"ResetAuthorTooltip": "将提交作者重置为当前配置的用户。这也将更新作者的时间戳",
|
||||
"SetAuthor": "设置作者",
|
||||
"SetAuthorTooltip": "基于提示设置作者",
|
||||
"AddCoAuthor": "添加共同作者",
|
||||
"AmendCommitAttribute": "修补提交属性",
|
||||
"AmendCommitAttributeTooltip": "设置或重置提交的作者,或添加其他作者。",
|
||||
"SetAuthorPromptTitle": "设置作者(格式为 'Name <Email>')",
|
||||
"AddCoAuthorPromptTitle": "添加共同作者(格式为 'Name <Email>')",
|
||||
"AddCoAuthorTooltip": "添加共同作者 使用GitHub/GitLab元数据共同作者(Co-authored-by)",
|
||||
"SureResetCommitAuthor": "将更新提交的作者名称,同时也将更新提交时间,是否继续?",
|
||||
"RewordCommitEditor": "使用编辑器重命名提交",
|
||||
"NoCommitsThisBranch": "该分支没有提交",
|
||||
"UpdateRefHere": "更新分支到 '{{.ref}}'",
|
||||
"ExecCommandHere": "在这里执行以下命令:",
|
||||
"Error": "错误",
|
||||
"Undo": "撤销",
|
||||
"UndoReflog": "(通过 reflog)撤销「实验功能」",
|
||||
"RedoReflog": "(通过 reflog)重做「实验功能」",
|
||||
"UndoReflog": "(通过 reflog)撤销「实验功能」",
|
||||
"RedoReflog": "(通过 reflog)重做「实验功能」",
|
||||
"UndoTooltip": "Reflog将用于确定运行哪个git命令来撤消最后一个git命令。这并不包括对工作树的更改,只考虑提交。",
|
||||
"RedoTooltip": "Reflog将用于确定运行哪个git命令来重做上一个git命令。这并不包括对工作树的更改,只考虑提交。",
|
||||
"UndoMergeResolveTooltip": "撤消上次合并冲突解决",
|
||||
"DiscardAllTooltip": "丢弃'{{.path}}'中已暂存和未暂存的变更",
|
||||
"DiscardUnstagedTooltip": "丢弃'{{.path}}'中未暂存的变更",
|
||||
"DiscardUnstagedDisabled": "选中的项目既没有已暂存的变更也没有未暂存的变更",
|
||||
"Pop": "应用并删除",
|
||||
"StashPopTooltip": "将存储项应用到工作目录并删除存储项。",
|
||||
"Drop": "删除",
|
||||
"StashDropTooltip": "从贮藏列表中删除该贮藏项",
|
||||
"Apply": "应用",
|
||||
"StashApplyTooltip": "将贮藏项应用到您的工作目录。",
|
||||
"NoStashEntries": "没有贮藏条目",
|
||||
"StashDrop": "删除贮藏",
|
||||
"SureDropStashEntry": "您确定要删除此贮藏条目吗?",
|
||||
@@ -86,27 +183,47 @@
|
||||
"StashApply": "应用贮藏",
|
||||
"SureApplyStashEntry": "您确定要应用此贮藏条目?",
|
||||
"NoTrackedStagedFilesStash": "没有可以贮藏的已跟踪/暂存文件",
|
||||
"StashChanges": "贮藏更改",
|
||||
"NoFilesToStash": "没有需要贮藏的文件",
|
||||
"StashChanges": "贮藏变更",
|
||||
"RenameStash": "重命名贮藏",
|
||||
"RenameStashPrompt": "重命名贮藏: {{.stashName}}",
|
||||
"OpenConfig": "打开配置文件",
|
||||
"EditConfig": "编辑配置文件",
|
||||
"ForcePush": "强制推送",
|
||||
"ForcePushPrompt": "您的分支已与远程分支不同。按‘esc’取消,或‘enter’强制推送.",
|
||||
"ForcePushDisabled": "您的分支已与远程分支不同, 并且您已经禁用了强行推送",
|
||||
"UpdatesRejected": "更新被拒绝。在下次推送前,请先抓取并检查远程分支。",
|
||||
"UpdatesRejectedAndForcePushDisabled": "更新被拒绝,您已禁用强制推送",
|
||||
"CheckForUpdate": "检查更新",
|
||||
"CheckingForUpdates": "正在检查更新…",
|
||||
"UpdateAvailableTitle": "有可用更新!",
|
||||
"UpdateAvailable": "下载并安装版本 {{.newVersion}}?",
|
||||
"UpdateInProgressWaitingStatus": "更新中",
|
||||
"UpdateCompletedTitle": "更新完成!",
|
||||
"UpdateCompleted": "已成功安装更新,重新启动 lazygit 使其生效。",
|
||||
"FailedToRetrieveLatestVersionErr": "检索版本信息失败",
|
||||
"OnLatestVersionErr": "已是最新版本",
|
||||
"MajorVersionErr": "新版本 ({{.newVersion}}) 与当前版本 ({{.currentVersion}}) 相比,具有非向后兼容的更改",
|
||||
"MajorVersionErr": "新版本({{.newVersion}})与当前版本({{.currentVersion}})相比,具有非向后兼容的更改",
|
||||
"CouldNotFindBinaryErr": "在 {{.url}} 处找不到任何二进制文件",
|
||||
"UpdateFailedErr": "更新失败: {{.errMessage}}",
|
||||
"ConfirmQuitDuringUpdateTitle": "当前正在更新中...",
|
||||
"ConfirmQuitDuringUpdate": "当前正在更新中,你确定要退出吗?",
|
||||
"MergeToolTitle": "合并工具",
|
||||
"MergeToolPrompt": "确定要打开 `git mergetool` 吗?",
|
||||
"IntroPopupMessage": "\n感谢使用 lazygit!你真的太棒了。下面几点你可能会感兴趣:\n\n 1) 观看此视频,快速了解 lazygit 的功能:\n https://youtu.be/CPLdltN7wgE\n\n 2) 记得看看最新发行说明:\n https://github.com/jesseduffield/lazygit/releases\n\n 3) 使用 git 说明你是一位程序员!你可以和我们一起让 lazygit 变得更好。\n 考虑为本项目做些贡献吧:\n https://github.com/jesseduffield/lazygit\n 你也可以直接赞助,并告诉我哪里需要改进,点右下角的捐赠按钮就好了。\n 哪怕只是给仓库点个星星也很棒!\n",
|
||||
"IntroPopupMessage": "\n感谢使用 lazygit!你真的太棒了。下面几点你可能会感兴趣:\n\n 1) 观看此视频,快速了解 lazygit 的功能:\n https://youtu.be/CPLdltN7wgE\n\n 2) 记得看看最新发行说明:\n https://github.com/jesseduffield/lazygit/releases\n\n 3) 使用 git 说明你是一位程序员!你可以和我们一起让 lazygit 变得更好。\n 考虑为本项目做些贡献吧:\n https://github.com/jesseduffield/lazygit\n 你也可以直接赞助,并告诉我哪里需要改进,点右下角的捐赠按钮就好了。\n 哪怕只是给仓库点个星星也很棒!\n",
|
||||
"DeprecatedEditConfigWarning": "englishDeprecatedEditConfigWarning",
|
||||
"GitconfigParseErr": "由于存在未加引号的'\\'字符,因此 Gogit 无法解析您的 gitconfig 文件。删除它们应该可以解决问题。",
|
||||
"EditFile": "编辑文件",
|
||||
"EditFileTooltip": "使用外部编辑器打开文件",
|
||||
"OpenFile": "打开文件",
|
||||
"OpenFileTooltip": "使用默认程序打开该文件",
|
||||
"OpenInEditor": "在编辑器中编写",
|
||||
"IgnoreFile": "添加到 .gitignore",
|
||||
"ExcludeFile": "添加到 .git/info/exclude",
|
||||
"RefreshFiles": "刷新文件",
|
||||
"Merge": "合并到当前检出的分支",
|
||||
"RegularMerge": "常规合并",
|
||||
"MergeBranchTooltip": "Merge selected branch into currently checked out branch.",
|
||||
"ConfirmQuit": "您确定要退出吗?",
|
||||
"SwitchRepo": "切换到最近的仓库",
|
||||
"AllBranchesLogGraph": "显示所有分支的日志",
|
||||
@@ -114,31 +231,48 @@
|
||||
"CopyPullRequestURL": "将抓取请求 URL 复制到剪贴板",
|
||||
"NoBranchOnRemote": "该分支在远程上不存在. 您需要先将其推送到远程.",
|
||||
"Fetch": "抓取",
|
||||
"FetchTooltip": "从远程获取变更",
|
||||
"NoAutomaticGitFetchTitle": "无法自动进行 \"git fetch\"",
|
||||
"NoAutomaticGitFetchBody": "Lazygit 不能在私人仓库中使用 \"git fetch\"; 请在文件面板中使用 'f' 手动运行 \"git fetch\"",
|
||||
"FileEnter": "暂存单个 块/行 用于文件, 或 折叠/展开 目录",
|
||||
"FileEnterTooltip": "如果选中的是一个文件,则会进入到暂存视图,以便可以暂存单个代码块/行。如果选中的是一个目录,则会折叠/展开这个目录",
|
||||
"FileStagingRequirements": "只能暂存跟踪文件的单独行",
|
||||
"StageSelectionTooltip": "切换行暂存状态",
|
||||
"DiscardSelection": "取消变更 (git reset)",
|
||||
"ToggleSelectHunk": "切换选择区块",
|
||||
"DiscardSelection": "取消变更(git reset)",
|
||||
"DiscardSelectionTooltip": "当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更",
|
||||
"ToggleSelectHunk": "切换选择代码块",
|
||||
"ToggleSelectHunkTooltip": "切换代码块选择模式",
|
||||
"ToggleSelectionForPatch": "添加/移除 行到补丁",
|
||||
"EditHunk": "编辑代码块",
|
||||
"EditHunkTooltip": "在外部编辑器中编辑选中的代码块",
|
||||
"ToggleStagingView": "切换到其他面板",
|
||||
"ToggleStagingViewTooltip": "切换到其他视图(已暂存/未暂存的变更)",
|
||||
"ReturnToFilesPanel": "返回文件面板",
|
||||
"FastForward": "从上游快进此分支",
|
||||
"FastForwardTooltip": "将当前分支直接移动到远程追踪分支的最新提交",
|
||||
"FastForwarding": "抓取并快进",
|
||||
"FoundConflictsTitle": "自动合并失败",
|
||||
"ViewConflictsMenuItem": "查看冲突",
|
||||
"AbortMenuItem": "关于 %s",
|
||||
"PickHunk": "选中区块",
|
||||
"PickAllHunks": "选中所有区块",
|
||||
"ViewMergeRebaseOptions": "查看 合并/变基 选项",
|
||||
"ViewMergeRebaseOptionsTooltip": "查看当前合并或变基的中止、继续、跳过选项",
|
||||
"ViewMergeOptions": "查看 合并(merge) 选项",
|
||||
"ViewRebaseOptions": "View rebase opGlobalTitletions",
|
||||
"NotMergingOrRebasing": "您目前既不进行变基也不进行合并",
|
||||
"AlreadyRebasing": "在变基时无法执行此操作",
|
||||
"RecentRepos": "最近的仓库",
|
||||
"MergeOptionsTitle": "合并选项",
|
||||
"RebaseOptionsTitle": "变基选项",
|
||||
"CommitSummaryTitle": "提交讯息",
|
||||
"CommitSummaryTitle": "提交信息",
|
||||
"CommitDescriptionTitle": "提交信息说明",
|
||||
"CommitDescriptionSubTitle": "按 {{.togglePanelKeyBinding}} 键切换焦点, {{.commitMenuKeybinding}} 打开菜单",
|
||||
"LocalBranchesTitle": "分支页面",
|
||||
"SearchTitle": "搜索",
|
||||
"TagsTitle": "标签页面",
|
||||
"MenuTitle": "菜单",
|
||||
"CommitMenuTitle": "提交 菜单",
|
||||
"RemotesTitle": "远程页面",
|
||||
"RemoteBranchesTitle": "远程分支",
|
||||
"PatchBuildingTitle": "构建补丁中",
|
||||
@@ -146,17 +280,33 @@
|
||||
"SecondaryTitle": "次要",
|
||||
"ReflogCommitsTitle": "Reflog 页面",
|
||||
"ConflictsResolved": "已解决所有冲突。是否继续?",
|
||||
"Continue": "继续",
|
||||
"RebasingTitle": "变基 '{{.checkedOutBranch}}'",
|
||||
"RebasingFromBaseCommitTitle": "从标记的几点变基'{{.checkedOutBranch}}'",
|
||||
"SimpleRebase": "简单变基到 '{{.ref}}'",
|
||||
"InteractiveRebase": "交互式变基到 '{{.ref}}'",
|
||||
"RebaseOntoBaseBranch": "变基到主分支 ({{.baseBranch}})",
|
||||
"InteractiveRebaseTooltip": "由于交互式变基被中断,所以你可以在继续变基之前更新TODO提交。",
|
||||
"RebaseOntoBaseBranchTooltip": "将已检出的分支变基到主分支上 (例如:最近的主分支).",
|
||||
"MustSelectTodoCommits": "在变基过程中, 该操作仅在选中TODO提交时有效。",
|
||||
"FwdNoUpstream": "此分支没有上游,无法快进",
|
||||
"FwdNoLocalUpstream": "此分支的远程未在本地注册,无法快进",
|
||||
"FwdCommitsToPush": "此分支带有尚未推送的提交,无法快进",
|
||||
"PullRequestNoUpstream": "没有设置上游的分支无法执行拉取请求",
|
||||
"ErrorOccurred": "发生错误!请在以下位置创建 issue",
|
||||
"NoRoom": "空间不足",
|
||||
"YouAreHere": "您在这里",
|
||||
"YouDied": "你死了!",
|
||||
"RewordNotSupported": "当前不支持交互式重新基准化时的重新措词提交",
|
||||
"CherryPickCopy": "复制提交(拣选)",
|
||||
"PasteCommits": "粘贴提交(拣选)",
|
||||
"ChangingThisActionIsNotAllowed": "不允许更改这类变基待办项目",
|
||||
"CherryPickCopy": "复制提交(拣选)",
|
||||
"CherryPickCopyTooltip": "标记提交为已复制。然后,在本地提交视图中,你可以按 `{{.paste}}` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `{{.escape}}` 来取消选择。",
|
||||
"CherryPickCopyRangeTooltip": "将上次已复制的提交到当前选中的提交都标记为已复制",
|
||||
"PasteCommits": "粘贴提交(拣选)",
|
||||
"SureCherryPick": "您确定要将选中的提交进行拣选到这个分支吗?",
|
||||
"CherryPick": "拣选 (Cherry-Pick)",
|
||||
"CherryPick": "拣选(Cherry-Pick)",
|
||||
"CannotCherryPickNonCommit": "无法拣选TODO类型的提交",
|
||||
"CannotCherryPickMergeCommit": "不支持拣选合并类型的提交",
|
||||
"Donate": "捐助",
|
||||
"AskQuestion": "提问咨询",
|
||||
"PrevLine": "选择上一行",
|
||||
@@ -171,71 +321,128 @@
|
||||
"ScrollUp": "向上滚动",
|
||||
"ScrollUpMainWindow": "向上滚动主面板",
|
||||
"ScrollDownMainWindow": "向下滚动主面板",
|
||||
"AmendCommitTitle": "修改提交",
|
||||
"AmendCommitPrompt": "您确定要使用暂存文件来修改此提交吗?",
|
||||
"AmendCommitTitle": "修补(amend)提交",
|
||||
"AmendCommitPrompt": "您确定要使用暂存文件来修补此提交吗?",
|
||||
"DropCommitTitle": "删除提交",
|
||||
"DropCommitPrompt": "您确定要删除此提交吗?",
|
||||
"DropUpdateRefPrompt": "您确定要删除选定的 update-ref 待办事项吗?除非中止变基,否则这是不可逆转的。",
|
||||
"PullingStatus": "正在拉取",
|
||||
"PushingStatus": "正在推送",
|
||||
"FetchingStatus": "正在抓取",
|
||||
"SquashingStatus": "正在压缩",
|
||||
"FixingStatus": "正在修正",
|
||||
"DeletingStatus": "正在删除",
|
||||
"DroppingStatus": "删除中...",
|
||||
"MovingStatus": "正在移动",
|
||||
"RebasingStatus": "正在变基",
|
||||
"AmendingStatus": "正在修改",
|
||||
"MergingStatus": "合并中...",
|
||||
"LowercaseRebasingStatus": "变基中...",
|
||||
"LowercaseMergingStatus": "合并中...",
|
||||
"AmendingStatus": "正在修补",
|
||||
"CherryPickingStatus": "正在拣选",
|
||||
"UndoingStatus": "正在撤销",
|
||||
"RedoingStatus": "正在重做",
|
||||
"CheckingOutStatus": "长子检出",
|
||||
"CheckingOutStatus": "正在检出",
|
||||
"CommittingStatus": "正在提交",
|
||||
"RevertingStatus": "还原中...",
|
||||
"CreatingFixupCommitStatus": "正在创建一个修复提交",
|
||||
"CommitFiles": "提交文件",
|
||||
"SubCommitsDynamicTitle": "提交 (%s)",
|
||||
"CommitFilesDynamicTitle": "比较文件差异 (%s)",
|
||||
"RemoteBranchesDynamicTitle": "远程分支 (%s)",
|
||||
"ViewItemFiles": "查看提交的文件",
|
||||
"ViewItemFilesTooltip": "查看所选项的修改文件",
|
||||
"CommitFilesTitle": "提交文件",
|
||||
"CheckoutCommitFileTooltip": "检出文件",
|
||||
"DiscardOldFileChangeTooltip": "放弃对此文件的提交更改",
|
||||
"DiscardFileChangesTitle": "放弃文件更改",
|
||||
"DiscardFileChangesPrompt": "您确定要舍弃此提交对该文件的更改吗?如果此文件是在此提交中创建的,它将被删除",
|
||||
"CanOnlyDiscardFromLocalCommits": "只能从本地提交中丢弃更改",
|
||||
"Remove": "删除",
|
||||
"DiscardOldFileChangeTooltip": "放弃对此文件的提交变更",
|
||||
"DiscardFileChangesTitle": "放弃文件变更",
|
||||
"DiscardFileChangesPrompt": "您确定要舍弃此提交对该文件的变更吗?如果此文件是在此提交中创建的,它将被删除",
|
||||
"DisabledForGPG": "该功能不适用于使用 GPG 的用户",
|
||||
"CreateRepo": "当前目录不在 git 仓库中。是否在此目录创建一个新的 git 仓库?(y/n): ",
|
||||
"BareRepo": "您已经尝试在空仓库中打开Lazygit,但是Lazygit还不支持空仓库。打开最近的仓库吗?(y / n) ",
|
||||
"InitialBranch": "分支名称? (git的默认值为空): ",
|
||||
"NoRecentRepositories": "必须在git存储库中打开lazygit。没有有效的最近存储库。即将退出...",
|
||||
"IncorrectNotARepository": "'notARepository'的值不正确。它应该是“prompt”,“create”,“skip”或“quit”中的一个。",
|
||||
"AutoStashTitle": "自动存储?",
|
||||
"AutoStashPrompt": "您必须隐藏并弹出更改以使更改生效。自动执行?(enter/esc)",
|
||||
"StashPrefix": "自动隐藏更改 ",
|
||||
"Discard": "查看'放弃更改'选项",
|
||||
"AutoStashPrompt": "您必须隐藏并弹出变更以使变更生效。自动执行?(enter/esc)",
|
||||
"StashPrefix": "自动隐藏变更 ",
|
||||
"Discard": "查看'放弃变更'选项",
|
||||
"DiscardChangesTitle": "放弃变更",
|
||||
"DiscardFileChangesTooltip": "查看选中文件的放弃变更选项",
|
||||
"Cancel": "取消",
|
||||
"DiscardAllChanges": "放弃所有更改",
|
||||
"DiscardAllChanges": "放弃所有变更",
|
||||
"DiscardUnstagedChanges": "放弃未暂存的变更",
|
||||
"DiscardAllChangesToAllFiles": "清空工作区",
|
||||
"DiscardAnyUnstagedChanges": "丢弃未暂存的变更",
|
||||
"DiscardUntrackedFiles": "丢弃未跟踪的文件",
|
||||
"DiscardStagedChanges": "丢弃已暂存的变更",
|
||||
"HardReset": "硬重置",
|
||||
"BranchDeleteTooltip": "查看本地/远程分支的删除选项",
|
||||
"TagDeleteTooltip": "查看本地/远程标签的删除选项",
|
||||
"Delete": "删除",
|
||||
"Reset": "重置",
|
||||
"ResetTooltip": "查看重置选项 (soft/mixed/hard) 用于重置到选择项",
|
||||
"ViewResetOptions": "查看重置选项",
|
||||
"FileResetOptionsTooltip": "查看工作树的重置选项(例如:清除工作树)。",
|
||||
"CreateFixupCommit": "为此提交创建修正",
|
||||
"CreateFixupCommitTooltip": "创建修正提交",
|
||||
"SquashAboveCommitsTooltip": "压缩在所选提交之上的所有“fixup!”提交(自动压缩)",
|
||||
"CreateAmendCommit": "创建 'amend!' 提交",
|
||||
"FixupMenu_Fixup": "修复提交",
|
||||
"FixupMenu_FixupTooltip": "允许你修复另一个提交并保持原本的提交信息",
|
||||
"FixupMenu_AmendWithChanges": "基于当前变动内容修改提交",
|
||||
"FixupMenu_AmendWithChangesTooltip": "允许你修复另一个提交并修改提交信息",
|
||||
"FixupMenu_AmendWithoutChanges": "修改提交(不含变动内容,类似reword)",
|
||||
"FixupMenu_AmendWithoutChangesTooltip": "允许您修改另一个提交的提交消息而不更改其内容",
|
||||
"SquashAboveCommitsTooltip": "压缩在所选提交之上的所有“fixup!”提交(自动压缩)",
|
||||
"SquashCommitsAboveSelectedTooltip": "压缩当前选中提交下的所有修复提交(自动压缩)",
|
||||
"SquashCommitsInCurrentBranchTooltip": "压缩当前分支中的所有修复提交(自动压缩)",
|
||||
"SquashAboveCommits": "应用该修复提交",
|
||||
"SquashCommitsInCurrentBranch": "在当前分支",
|
||||
"SquashCommitsAboveSelectedCommit": "在选定提交之上",
|
||||
"CannotSquashCommitsInCurrentBranch": "在当前分支中无法压缩提交:因为分离HEAD提交是一个合并提交或者已经存在于主分支中",
|
||||
"ExecuteCustomCommand": "执行自定义命令",
|
||||
"ExecuteCustomCommandTooltip": "弹出一个提示符,您可以在其中输入要执行的 shell 命令。不要与预配置的自定义命令混淆。",
|
||||
"CustomCommand": "自定义命令:",
|
||||
"CommitChangesWithoutHook": "提交更改而无需预先提交钩子",
|
||||
"CommitChangesWithoutHook": "提交变更而无需预先提交钩子",
|
||||
"SkipHookPrefixNotConfigured": "您尚未配置用于跳过钩子的提交消息前缀。请在您的配置中设置 `git.skipHookPrefix ='WIP'`",
|
||||
"ResetTo": "重置为",
|
||||
"ResetSoftTooltip": "将 HEAD 重置为所选提交,并将当前提交和所选提交之间的更改保留为已暂存更改。",
|
||||
"ResetMixedTooltip": "将 HEAD 重置为所选提交,并将当前提交和所选提交之间的更改保留为未暂存的更改。",
|
||||
"ResetHardTooltip": "将 HEAD 重置为所选提交,并丢弃当前提交和所选提交之间的所有更改,以及工作树中的所有当前修改。",
|
||||
"PressEnterToReturn": "按下 Enter 键返回 lazygit",
|
||||
"ViewStashOptions": "查看贮藏选项",
|
||||
"StashAllChanges": "将所有更改加入贮藏",
|
||||
"StashAllChangesKeepIndex": "将已暂存的更改加入贮藏",
|
||||
"ViewStashOptionsTooltip": "查看贮藏选项(例如:贮藏所有、贮藏已暂存变更、贮藏未暂存变更)",
|
||||
"Stash": "贮藏",
|
||||
"StashTooltip": "贮藏所有变更.若要使用其他贮藏变体,请使用查看贮藏选项快捷键",
|
||||
"StashAllChanges": "将所有变更加入贮藏",
|
||||
"StashStagedChanges": "贮藏已暂存变更",
|
||||
"StashAllChangesKeepIndex": "将已暂存的变更加入贮藏",
|
||||
"StashUnstagedChanges": "贮藏未暂存变更",
|
||||
"StashIncludeUntrackedChanges": "贮藏所有变更,包括未跟踪的文件",
|
||||
"StashOptions": "贮藏选项",
|
||||
"NotARepository": "错误:必须在 git 仓库中运行",
|
||||
"WorkingDirectoryDoesNotExist": "错误:当前工作目录不存在",
|
||||
"Jump": "跳到面板",
|
||||
"ScrollLeftRight": "左右滚动",
|
||||
"ScrollLeft": "向左滚动",
|
||||
"ScrollRight": "向右滚动",
|
||||
"DiscardPatch": "丢弃补丁",
|
||||
"DiscardPatchConfirm": "您一次只能通过一个提交或贮藏条目构建补丁。需要放弃当前补丁吗?",
|
||||
"DiscardPatchSameCommitConfirm": "您当前已将更改添加到此提交的补丁中。放弃当前补丁?",
|
||||
"CantPatchWhileRebasingError": "处于合并或变基状态时,您无法构建修补程序或运行修补程序命令",
|
||||
"ToggleAddToPatch": "补丁中包含的切换文件",
|
||||
"ToggleAddToPatchTooltip": "切换文件是否包含在自定义补丁中。请参阅 {{.doc}}。",
|
||||
"ToggleAllInPatch": "操作所有文件",
|
||||
"ToggleAllInPatchTooltip": "添加或删除所有提交中的文件到自定义的补丁中。请参阅 {{.doc}}。",
|
||||
"UpdatingPatch": "正在更新补丁",
|
||||
"ViewPatchOptions": "查看自定义补丁选项",
|
||||
"PatchOptionsTitle": "补丁选项",
|
||||
"NoPatchError": "尚未创建补丁。你可以在提交中的文件上按下“空格”或使用“回车”添加其中的特定行以开始构建补丁",
|
||||
"EnterCommitFile": "输入文件以将所选行添加到补丁中(或切换目录折叠)",
|
||||
"EmptyPatchError": "补丁还是空的。首先将一些文件或行添加到您的补丁中。",
|
||||
"EnterCommitFile": "输入文件以将所选行添加到补丁中(或切换目录折叠)",
|
||||
"EnterCommitFileTooltip": "如果已选择一个文件,则Enter进入该文件,以便您可以向自定义补丁添加/删除单独的行。如果选择了目录,则切换目录。",
|
||||
"ExitCustomPatchBuilder": "退出逐行模式",
|
||||
"EnterUpstream": "以这种格式输入上游:'<远程仓库> <分支名称>'",
|
||||
"InvalidUpstream": "上游格式无效,格式应当为:'<remote> <branchname>'",
|
||||
@@ -243,51 +450,92 @@
|
||||
"NewRemote": "添加新的远程仓库",
|
||||
"NewRemoteName": "新远程仓库名称:",
|
||||
"NewRemoteUrl": "新远程仓库 URL:",
|
||||
"ViewBranches": "查看分支",
|
||||
"EditRemoteName": "输入远程仓库 {{.remoteName}} 的新名称:",
|
||||
"EditRemoteUrl": "输入远程仓库 {{.remoteName}} 的新 URL:",
|
||||
"RemoveRemote": "删除远程",
|
||||
"RemoveRemoteTooltip": "删除选中的远程。从远程跟踪远程分支的任何本地分支都不会受到影响。",
|
||||
"RemoveRemotePrompt": "您确定要删除远程仓库吗?",
|
||||
"DeleteRemoteBranch": "删除远程分支",
|
||||
"DeleteRemoteBranchMessage": "您确定要删除远程分支吗?",
|
||||
"DeleteRemoteBranchTooltip": "从远程删除远程分支。",
|
||||
"SetAsUpstream": "设置为上游",
|
||||
"SetAsUpstreamTooltip": "设置为检出分支的上游",
|
||||
"SetUpstream": "设置为检出分支的上游",
|
||||
"UnsetUpstream": "取消已选分支的上游",
|
||||
"ViewDivergenceFromUpstream": "查看与上游的差异",
|
||||
"ViewDivergenceFromBaseBranch": "查看主分支({{.baseBranch}})与上游的差异",
|
||||
"CouldNotDetermineBaseBranch": "无法确定主分支",
|
||||
"DivergenceSectionHeaderLocal": "本地",
|
||||
"DivergenceSectionHeaderRemote": "远端",
|
||||
"ViewUpstreamResetOptions": "重置已检出的分支到上游{{.upstream}}",
|
||||
"ViewUpstreamResetOptionsTooltip": "查看用于将检出分支重置到 {{upstream}} 的选项。注意:这不会将选定的分支重置到上游,而是将检出的分支重置到上游。",
|
||||
"ViewUpstreamRebaseOptions": "将检出分支的上游重新设置为 {{.upstream}}",
|
||||
"ViewUpstreamRebaseOptionsTooltip": "查看将检出分支变基到 {{upstream}} 的选项。注意:这不会将所选分支重新设置为上游,而是将检出分支重新设置为上游。",
|
||||
"UpstreamGenericName": "所选分支的上游",
|
||||
"SetUpstreamTitle": "设置上游分支",
|
||||
"SetUpstreamMessage": "您确定要将 {{.checkedOut}} 的上游分支设置为 {{.selected}} 吗?",
|
||||
"EditRemoteTooltip": "编辑远程仓库",
|
||||
"TagCommit": "标签提交",
|
||||
"TagCommitTooltip": "创建一个新标签指向所选提交。你可以在弹窗中输入标签名称和描述(可选)。",
|
||||
"TagMenuTitle": "创建标签",
|
||||
"TagNameTitle": "标签名称",
|
||||
"TagMessageTitle": "标签消息",
|
||||
"LightweightTag": "轻量标签",
|
||||
"AnnotatedTag": "附注标签",
|
||||
"DeleteTagTitle": "要删除 '{{.tagName}}' 标签?",
|
||||
"DeleteLocalTag": "删除本地标签",
|
||||
"DeleteRemoteTag": "删除远程标签",
|
||||
"SelectRemoteTagUpstream": "被删除标签'{{.tagName}}'的远端",
|
||||
"DeleteRemoteTagPrompt": "你确定要从'{{.upstream}}'中删除远程标签'{{.tagName}}'吗?",
|
||||
"RemoteTagDeletedMessage": "远程标签已删除",
|
||||
"PushTagTitle": "将 {{.tagName}} 推送到远程仓库:",
|
||||
"PushTag": "推送标签",
|
||||
"PushTagTooltip": "推送选择的标签到远端。你将在弹窗中选择一个远端。",
|
||||
"NewTag": "创建标签",
|
||||
"NewTagTooltip": "基于当前提交创建一个新标签。你将在弹窗中输入标签名称和描述(可选)。",
|
||||
"CreatingTag": "创建标签",
|
||||
"ForceTag": "强制标记标签",
|
||||
"ForceTagPrompt": "该标签‘{{.tagName}}’已存在。请按{{.cancelKey}}取消,或者按{{.confirmKey}}覆盖它。",
|
||||
"FetchRemoteTooltip": "抓取远程仓库",
|
||||
"FetchingRemoteStatus": "抓取远程仓库中",
|
||||
"CheckoutCommit": "检出提交",
|
||||
"CheckoutCommitTooltip": "检出所选择的提交作为分离HEAD。",
|
||||
"SureCheckoutThisCommit": "您确定要检出此提交吗?",
|
||||
"GitFlowOptions": "显示 git-flow 选项",
|
||||
"NotAGitFlowBranch": "这似乎不是 git flow 分支",
|
||||
"NewBranchNamePrompt": "输入分支的新名称",
|
||||
"IgnoreTracked": "忽略跟踪文件",
|
||||
"ExcludeTracked": "排除跟踪文件",
|
||||
"IgnoreTrackedPrompt": "您确定要忽略已跟踪的文件吗?",
|
||||
"ExcludeTrackedPrompt": "您确定要排除已跟踪的文件吗?",
|
||||
"ViewResetToUpstreamOptions": "查看上游重置选项",
|
||||
"NextScreenMode": "下一屏模式(正常/半屏/全屏)",
|
||||
"NextScreenMode": "下一屏模式(正常/半屏/全屏)",
|
||||
"PrevScreenMode": "上一屏模式",
|
||||
"StartSearch": "开始搜索",
|
||||
"StartFilter": "通过文本过滤当前视图",
|
||||
"Panel": "面板",
|
||||
"Keybindings": "按键绑定",
|
||||
"KeybindingsLegend": "图例:`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b",
|
||||
"KeybindingsMenuSectionLocal": "本地",
|
||||
"KeybindingsMenuSectionGlobal": "全局",
|
||||
"KeybindingsMenuSectionNavigation": "导航",
|
||||
"RenameBranch": "重命名分支",
|
||||
"Upstream": "上游",
|
||||
"UpstreamTooltip": "查看所选分支的上游选项,例如设置/取消设置上游和重置为上游。",
|
||||
"BranchUpstreamOptionsTitle": "上游选项",
|
||||
"ViewBranchUpstreamOptions": "查看上游选项",
|
||||
"ViewBranchUpstreamOptionsTooltip": "查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。",
|
||||
"UpstreamNotSetError": "所选分支没有上游(或者上游没有存储在本地)",
|
||||
"NewGitFlowBranchPrompt": "新的 {{.branchType}} 名称:",
|
||||
"RenameBranchWarning": "该分支正在跟踪远程仓库。此操作将仅会重命名本地分支名称,而不会重命名远程分支的名称。确定继续?",
|
||||
"OpenKeybindingsMenu": "打开菜单",
|
||||
"ResetCherryPick": "重置已拣选(复制)的提交",
|
||||
"ResetCherryPick": "重置已拣选(复制)的提交",
|
||||
"NextTab": "下一个标签",
|
||||
"PrevTab": "上一个标签",
|
||||
"CantUndoWhileRebasing": "进行基础调整时无法撤消",
|
||||
"CantRedoWhileRebasing": "变基时无法重做",
|
||||
"MustStashWarning": "将补丁拉出到索引中需要存储和取消存储所做的更改。如果出现问题,您将可以从存储中访问文件。继续?",
|
||||
"MustStashWarning": "将补丁拉出到索引中需要存储和取消存储所做的变更。如果出现问题,您将可以从存储中访问文件。继续?",
|
||||
"MustStashTitle": "必须保存进度",
|
||||
"ConfirmationTitle": "确认面板",
|
||||
"PrevPage": "上一页",
|
||||
@@ -295,13 +543,17 @@
|
||||
"GotoTop": "滚动到顶部",
|
||||
"GotoBottom": "滚动到底部",
|
||||
"FilteringBy": "过滤依据",
|
||||
"ResetInParentheses": "(重置)",
|
||||
"ResetInParentheses": "(重置)",
|
||||
"OpenFilteringMenu": "查看按路径过滤选项",
|
||||
"OpenFilteringMenuTooltip": "查看用于过滤提交日志的选项,以便仅显示与过滤器匹配的提交。",
|
||||
"FilterBy": "过滤",
|
||||
"ExitFilterMode": "停止按路径过滤",
|
||||
"FilterPathOption": "输入要过滤的路径",
|
||||
"FilterAuthorOption": "输入作者进行过滤",
|
||||
"EnterFileName": "输入路径:",
|
||||
"EnterAuthor": "输入作者:",
|
||||
"FilteringMenuTitle": "正在过滤",
|
||||
"WillCancelExistingFilterTooltip": "注意:这将取消现有的过滤器",
|
||||
"MustExitFilterModeTitle": "命令不可用",
|
||||
"MustExitFilterModePrompt": "命令在过滤模式下不可用。退出过滤模式?",
|
||||
"Diff": "差异",
|
||||
@@ -311,10 +563,22 @@
|
||||
"DiffingMenuTitle": "正在 diff",
|
||||
"SwapDiff": "反向 diff",
|
||||
"ViewDiffingOptions": "打开 diff 菜单",
|
||||
"ViewDiffingOptionsTooltip": "查看与比较两个引用相关的选项,例如与选定的 ref 进行比较,输入要比较的 ref,然后反转比较方向。",
|
||||
"OpenCommandLogMenu": "打开命令日志菜单",
|
||||
"OpenCommandLogMenuTooltip": "查看命令日志的选项,例如显示/隐藏命令日志以及聚焦命令日志",
|
||||
"ShowingGitDiff": "显示输出:",
|
||||
"CommitDiff": "比较提交差异",
|
||||
"CopyCommitHashToClipboard": "将提交的 hash 复制到剪贴板",
|
||||
"CommitHash": "提交的 hash",
|
||||
"CommitURL": "提交URL",
|
||||
"CopyCommitMessageToClipboard": "将提交消息复制到剪贴板",
|
||||
"PasteCommitMessageFromClipboard": "从剪贴板粘贴提交信息",
|
||||
"SurePasteCommitMessage": "粘贴将覆盖当前提交消息,继续吗?",
|
||||
"CommitMessage": "提交信息",
|
||||
"CommitSubject": "提交主题",
|
||||
"CommitAuthor": "作者",
|
||||
"CopyCommitAttributeToClipboard": "复制提交属性到剪贴板",
|
||||
"CopyCommitAttributeToClipboardTooltip": "复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。",
|
||||
"CopyBranchNameToClipboard": "将分支名称复制到剪贴板",
|
||||
"CopyPathToClipboard": "将文件名复制到剪贴板",
|
||||
"CommitPrefixPatternError": "提交前缀模式错误",
|
||||
@@ -323,18 +587,21 @@
|
||||
"NoFilesStagedPrompt": "您尚未暂存任何文件。提交所有文件?",
|
||||
"BranchNotFoundTitle": "找不到分支",
|
||||
"BranchNotFoundPrompt": "找不到分支。创建一个新分支命名为:",
|
||||
"BranchUnknown": "未知的分支",
|
||||
"DiscardChangeTitle": "取消暂存选中的行",
|
||||
"DiscardChangePrompt": "您确定要删除所选的行(git reset)吗?这是不可逆的。\n要禁用此对话框,请将 'gui.skipDiscardChangeWarning' 的配置键设置为 true",
|
||||
"DiscardChangePrompt": "您确定要删除所选的行(git reset)吗?这是不可逆的。\n要禁用此对话框,请将 'gui.skipDiscardChangeWarning' 的配置键设置为 true",
|
||||
"CreateNewBranchFromCommit": "从提交创建新分支",
|
||||
"BuildingPatch": "正在构建补丁",
|
||||
"ViewCommits": "查看提交",
|
||||
"MinGitVersionError": "Git 版本必须至少为 2.20(即从 2018 年开始的版本)。请更新 git。或者在 https://github.com/jesseduffield/lazygit/issues 上提出一个问题,以使 lazygit 更加向后兼容。",
|
||||
"MinGitVersionError": "Git 版本必须至少为 2.20(即从 2018 年开始的版本)。请更新 git。或者在 https://github.com/jesseduffield/lazygit/issues 上提出一个问题,以使 lazygit 更加向后兼容。",
|
||||
"RunningCustomCommandStatus": "正在运行自定义命令",
|
||||
"SubmoduleStashAndReset": "存放未提交的子模块更改和更新",
|
||||
"SubmoduleStashAndReset": "存放未提交的子模块变更和更新",
|
||||
"AndResetSubmodules": "和重置子模块",
|
||||
"EnterSubmoduleTooltip": "输入子模块",
|
||||
"Enter": "进入",
|
||||
"CopySubmoduleNameToClipboard": "将子模块名称复制到剪贴板",
|
||||
"RemoveSubmodule": "删除子模块",
|
||||
"RemoveSubmoduleTooltip": "删除选定的子模块及其相应的目录",
|
||||
"RemoveSubmodulePrompt": "您确定要删除子模块 '%s' 及其对应的目录吗?这是不可逆的。",
|
||||
"ResettingSubmoduleStatus": "正在重置子模块",
|
||||
"NewSubmoduleName": "新的子模块名称:",
|
||||
@@ -347,6 +614,8 @@
|
||||
"EditSubmoduleUrl": "更新子模块 URL",
|
||||
"InitializingSubmoduleStatus": "正在初始化子模块",
|
||||
"InitSubmoduleTooltip": "初始化子模块",
|
||||
"Update": "更新",
|
||||
"Initialize": "初始化",
|
||||
"SubmoduleUpdateTooltip": "更新子模块",
|
||||
"UpdatingSubmoduleStatus": "正在更新子模块",
|
||||
"BulkInitSubmodules": "批量初始化子模块",
|
||||
@@ -359,15 +628,22 @@
|
||||
"SubmodulesTitle": "子模块",
|
||||
"NavigationTitle": "列表面板导航",
|
||||
"SuggestionsCheatsheetTitle": "意见建议",
|
||||
"SuggestionsTitle": "意见建议 (点击 %s 以聚焦)",
|
||||
"SuggestionsTitle": "意见建议(按 %s 键以切换焦点)",
|
||||
"SuggestionsSubtitle": "(按 %s 键进行删除, %s 键进行编辑)",
|
||||
"ExtrasTitle": "附加",
|
||||
"PushingTagStatus": "推送标签",
|
||||
"PullRequestURLCopiedToClipboard": "抓取请求网址已复制到剪贴板",
|
||||
"CommitMessageCopiedToClipboard": "提交消息复制到剪贴板",
|
||||
"CommitDiffCopiedToClipboard": "复制提交差异到剪贴板",
|
||||
"CommitURLCopiedToClipboard": "复制提交URL到剪贴板",
|
||||
"CommitMessageCopiedToClipboard": "复制提交消息到剪贴板",
|
||||
"CommitSubjectCopiedToClipboard": "复制提交主题到剪贴板",
|
||||
"CommitAuthorCopiedToClipboard": "复制作者到剪贴板",
|
||||
"PatchCopiedToClipboard": "已复制补丁内容到剪贴板",
|
||||
"CopiedToClipboard": "复制到剪贴板",
|
||||
"ErrCannotEditDirectory": "无法编辑目录:您只能编辑单个文件",
|
||||
"ErrStageDirWithInlineMergeConflicts": "无法 暂存/取消暂存 包含具有内联合并冲突的文件的目录。请先解决合并冲突",
|
||||
"ErrRepositoryMovedOrDeleted": "找不到仓库。它可能已被移动或删除 ¯\\_(ツ)_/¯",
|
||||
"ErrWorktreeMovedOrRemoved": "找不到工作树,它可能被删除或者移走了。 ¯\\\\_(ツ)_/¯",
|
||||
"CommandLog": "命令日志",
|
||||
"ToggleShowCommandLog": "切换 显示/隐藏 命令日志",
|
||||
"FocusCommandLog": "焦点命令日志",
|
||||
@@ -375,8 +651,14 @@
|
||||
"RandomTip": "随机小提示",
|
||||
"SelectParentCommitForMerge": "选择父提交进行合并",
|
||||
"ToggleWhitespaceInDiffView": "切换是否在差异视图中显示空白字符差异",
|
||||
"ToggleWhitespaceInDiffViewTooltip": "切换是否在diff视图中显示空白更改",
|
||||
"IgnoreWhitespaceDiffViewSubTitle": "(忽略空白)",
|
||||
"IgnoreWhitespaceNotSupportedHere": "该视图不支持忽略空白",
|
||||
"IncreaseContextInDiffView": "扩大差异视图中显示的上下文范围",
|
||||
"IncreaseContextInDiffViewTooltip": "增加diff视图中围绕更改显示的上下文数量",
|
||||
"DecreaseContextInDiffView": "缩小差异视图中显示的上下文范围",
|
||||
"DecreaseContextInDiffViewTooltip": "减少diff视图中围绕更改显示的上下文数量",
|
||||
"DiffContextSizeChanged": "将diff上下文大小更改为%d",
|
||||
"CreatePullRequestOptions": "创建抓取请求选项",
|
||||
"DefaultBranch": "默认分支",
|
||||
"SelectBranch": "选择分支",
|
||||
@@ -387,60 +669,178 @@
|
||||
"LoadingCommits": "正在加载提交",
|
||||
"MustSpecifyOriginError": "指定分支时,必须同时指定远程",
|
||||
"GitOutput": "Git 输出:",
|
||||
"GitCommandFailed": "Git 命令执行失败。查看命令日志了解详情 (使用 %s 打开)",
|
||||
"GitCommandFailed": "Git 命令执行失败。查看命令日志了解详情(使用 %s 打开)",
|
||||
"AbortTitle": "放弃 %s",
|
||||
"AbortPrompt": "您确定要放弃当前 %s 吗?",
|
||||
"OpenLogMenu": "打开日志菜单",
|
||||
"OpenLogMenuTooltip": "查看提交日志的选项,例如更改排序顺序、隐藏 git graph、显示整个 git graph。",
|
||||
"LogMenuTitle": "提交日志选项",
|
||||
"ToggleShowGitGraphAll": "切换显示完整 git 分支图 (向 `git log` 命令传入 `--all` 选项)",
|
||||
"ToggleShowGitGraphAll": "切换显示完整 git 分支图(向 `git log` 命令传入 `--all` 选项)",
|
||||
"ShowGitGraph": "显示 git 分支图",
|
||||
"SortOrder": "排序",
|
||||
"SortAlphabetical": "字母顺序",
|
||||
"SortByDate": "日期大小",
|
||||
"SortByRecency": "新旧程度",
|
||||
"SortBasedOnReflog": "(基于reflog)",
|
||||
"SortCommits": "提交排序",
|
||||
"CantChangeContextSizeError": "无法在补丁构建模式下更改上下文,因为我们在发布该功能时懒得支持它。 如果你真的想要这么做,请告诉我们!",
|
||||
"CantChangeContextSizeError": "无法在补丁构建模式下变更上下文,因为我们在发布该功能时懒得支持它。 如果你真的想要这么做,请告诉我们!",
|
||||
"OpenCommitInBrowser": "在浏览器中打开提交",
|
||||
"ViewBisectOptions": "查看二分查找选项",
|
||||
"ConfirmRevertCommit": "你确定要恢复{{.selectedCommit}}?",
|
||||
"RewordInEditorTitle": "在编辑器中重写",
|
||||
"RewordInEditorPrompt": "您确定要在编辑器中重写此提交吗?",
|
||||
"CheckoutPrompt": "您确定要检出 '%s' 吗?",
|
||||
"HardResetAutostashPrompt": "您确定要硬重置到 '%s' 吗?如有必要,将执行自动贮藏。",
|
||||
"UpstreamGone": "(上游不存在)",
|
||||
"NukeDescription": "如果您想让工作树中的所有更改消失,可以这样做。如果存在受污染的子模块更改,这会将这些更改贮藏在子模块中。",
|
||||
"DiscardStagedChangesDescription": "这将创建一个仅包含已暂存更改的新贮藏条目,然后这些更改删除,以便工作树仅保留未暂存的更改。",
|
||||
"EmptyOutput": "<Empty output>",
|
||||
"Patch": "补丁",
|
||||
"CustomPatch": "自定义补丁",
|
||||
"CommitsCopied": "已复制这些提交",
|
||||
"CommitCopied": "已复制提交",
|
||||
"ResetPatch": "重置补丁",
|
||||
"ResetPatchTooltip": "清理当前补丁",
|
||||
"ApplyPatch": "应用补丁",
|
||||
"ApplyPatchTooltip": "应用当前补丁到工作树中",
|
||||
"ApplyPatchInReverse": "反向应用补丁",
|
||||
"ApplyPatchInReverseTooltip": "反向应用当前补丁到工作树中",
|
||||
"RemovePatchFromOriginalCommit": "从原来的提交 (%s) 中删除补丁",
|
||||
"RemovePatchFromOriginalCommitTooltip": "从这些提交中删除该补丁。这是通过在提交时启动交互式变基,反向应用补丁,然后继续变基来实现的。如果之后的提交依赖于补丁,您可能需要解决冲突。",
|
||||
"MovePatchOutIntoIndex": "将补丁移出到索引中",
|
||||
"MovePatchOutIntoIndexTooltip": "将补丁从提交中移出并移入到索引中。这是通过在提交时启动交互式变基、反向应用补丁、继续变基直至完成,然后将补丁应用到索引来实现的。如果之后的提交依赖于补丁,您可能需要解决冲突。",
|
||||
"MovePatchIntoNewCommit": "引入补丁到新提交中",
|
||||
"MovePatchIntoNewCommitTooltip": "将补丁从提交中移出并移至位于原始提交之上的新提交中。这是通过在原始提交处启动交互式变基,反向应用补丁,然后将补丁应用到索引并将其作为新提交提交,然后继续变基直至完成来实现的。如果以后的提交依赖于补丁,您可能需要解决冲突。",
|
||||
"MovePatchToSelectedCommit": "移动补丁到所选提交 (%s)",
|
||||
"MovePatchToSelectedCommitTooltip": "将补丁从其原始提交修改到选定的提交中。 实现这一点的方法是在原始提交时启动交互式重置,反向应用补丁, 然后在应用补丁和修改选定的提交之前,继续将其重新建立到选定的提交上。 重置将继续完成。如果源代码和目标代码提交之间的提交取决于补丁,您可能需要解决冲突。",
|
||||
"CopyPatchToClipboard": "复制补丁到剪贴板",
|
||||
"NoMatchesFor": "%s %s 没有匹配项",
|
||||
"MatchesFor": "正在匹配'%s' (%d of %d) %s",
|
||||
"SearchKeybindings": "%s: 下一个匹配项, %s: 上一个匹配项, %s: 退出搜索模式",
|
||||
"SearchPrefix": "搜索: ",
|
||||
"FilterPrefix": "过滤: ",
|
||||
"ExitSearchMode": "%s:退出搜索模式",
|
||||
"ExitTextFilterMode": "%s:退出过滤模式",
|
||||
"Switch": "切换",
|
||||
"SwitchToWorktree": "切换至工作树",
|
||||
"SwitchToWorktreeTooltip": "切换到选中的工作树",
|
||||
"AlreadyCheckedOutByWorktree": "该分支由工作树 {{.worktreeName}} 检出,您想切换到该工作树吗?",
|
||||
"BranchCheckedOutByWorktree": "该分支 {{.branchName}} 由工作树 {{.worktreeName}} 签出",
|
||||
"DetachWorktreeTooltip": "这将在工作树上运行“git checkout --detach”,以便它停止占用分支,但工作树的工作树将保持不变。",
|
||||
"Switching": "正在切换",
|
||||
"RemoveWorktree": "移除工作区",
|
||||
"RemoveWorktreeTitle": "移除工作区",
|
||||
"DetachWorktree": "分离工作树",
|
||||
"DetachingWorktree": "正在分离工作树",
|
||||
"WorktreesTitle": "工作区",
|
||||
"WorktreeTitle": "工作区",
|
||||
"RemoveWorktreePrompt": "你确定要删除工作树 {{.worktreeName}}' ?",
|
||||
"ForceRemoveWorktreePrompt": "'{{.worktreeName}}' 包含已修改或未跟踪的文件(说实话,它可能包含两者)。您确定要删除它吗?",
|
||||
"RemovingWorktree": "正在删除工作树",
|
||||
"AddingWorktree": "添加工作区",
|
||||
"CantDeleteCurrentWorktree": "您不能删除当前的工作树!",
|
||||
"AlreadyInWorktree": "您已经在选中的工作树",
|
||||
"CantDeleteMainWorktree": "您不能移除主工作树!",
|
||||
"NoWorktreesThisRepo": "没有工作区",
|
||||
"MissingWorktree": "(缺失)",
|
||||
"MainWorktree": "(主要)",
|
||||
"NewWorktree": "新建工作树",
|
||||
"NewWorktreePath": "新建工作树路径",
|
||||
"NewWorktreeBase": "新建工作树基于ref",
|
||||
"RemoveWorktreeTooltip": "删除选定的工作树。这将删除工作树的目录以及 .git 目录中有关工作树的元数据。",
|
||||
"BranchNameCannotBeBlank": "分支名称不能为空",
|
||||
"NewBranchName": "新分支名称",
|
||||
"NewBranchNameLeaveBlank": "新分支名称(为空则默认检出为 {{.default}})",
|
||||
"ViewWorktreeOptions": "查看工作区选项",
|
||||
"CreateWorktreeFrom": "从 {{.ref}} 创建工作树",
|
||||
"CreateWorktreeFromDetached": "从 {{.ref}} 创建工作树(分离)",
|
||||
"LcWorktree": "工作区",
|
||||
"ChangingDirectoryTo": "将目录更改为 {{.path}}",
|
||||
"Name": "名称",
|
||||
"Branch": "分支",
|
||||
"Path": "路径",
|
||||
"MarkedBaseCommitStatus": "已标记一个主提交用于变基",
|
||||
"MarkAsBaseCommit": "标记一个主提交用于变基",
|
||||
"MarkAsBaseCommitTooltip": "选择下一次变基的主提交。当您变基到一个分支时,只有高于主提交的提交才会被引入。这使用“git rebase --onto”命令。",
|
||||
"MarkedCommitMarker": "↑↑↑ 将从这里开始变基 ↑↑↑",
|
||||
"PleaseGoToURL": "清查看 {{.url}}",
|
||||
"NoCopiedCommits": "未复制提交",
|
||||
"DisabledMenuItemPrefix": "不可用: ",
|
||||
"QuickStartInteractiveRebase": "开始交互式变基",
|
||||
"QuickStartInteractiveRebaseTooltip": "为分支上的提交启动交互式变基。这将包括从 HEAD 提交到第一个合并提交或主分支提交的所有提交。\n如果您想从所选提交启动交互式变基,请按 `{{.editKey}}`。",
|
||||
"CannotQuickStartInteractiveRebase": "无法启动交互式变基:HEAD 提交是合并提交或存在于主分支上,因此没有适当的主提交来启动变基。您可以通过选择提交并按 `{{.editKey}}` 从特定提交启动交互式变基。",
|
||||
"ToggleRangeSelect": "切换拖动选择",
|
||||
"RangeSelectUp": "向上扩展选择范围",
|
||||
"RangeSelectDown": "向下扩展选择范围",
|
||||
"RangeSelectNotSupported": "该操作不支持范围选择,请选择单个项目",
|
||||
"NoItemSelected": "没有条目被选中",
|
||||
"SelectedItemIsNotABranch": "选中的条目不是一个分支",
|
||||
"SelectedItemDoesNotHaveFiles": "选中的条目中没有",
|
||||
"RangeSelectNotSupportedForSubmodules": "子模块不支持范围选择",
|
||||
"OldCherryPickKeyWarning": "The 'c' key is no longer the default key for copying commits to cherry pick. Please use `{{.copy}}` instead (and `{{.paste}}` to paste). The reason for this change is that the 'v' key for selecting a range of lines when staging is now also used for selecting a range of lines in any list view, meaning that we needed to find a new key for pasting commits, and if we're going to now use `{{.paste}}` for pasting commits, we may as well use `{{.copy}}` for copying them. If you want to configure the keybindings to get the old behaviour, set the following in your config:\n\nkeybinding:\n universal:\n toggleRangeSelect: <something other than v>\n commits:\n cherryPickCopy: 'c'\n pasteCommits: 'v'",
|
||||
"CommandDoesNotSupportOpeningInEditor": "该命令不支持切换到编辑器",
|
||||
"Actions": {
|
||||
"CheckoutCommit": "检出提交",
|
||||
"CheckoutTag": "检出标签",
|
||||
"CheckoutBranch": "检出分支",
|
||||
"ForceCheckoutBranch": "强制检出分支",
|
||||
"DeleteLocalBranch": "删除本地分支",
|
||||
"DeleteBranch": "删除分支",
|
||||
"Merge": "合并",
|
||||
"SquashMerge": "压缩合并",
|
||||
"RebaseBranch": "变基分支",
|
||||
"RenameBranch": "重命名分支",
|
||||
"CreateBranch": "建立分支",
|
||||
"FastForwardBranch": "快进分支",
|
||||
"CherryPick": "(拣选) 粘贴提交",
|
||||
"CheckoutFile": "检出文件",
|
||||
"DiscardOldFileChange": "放弃旧文件更改",
|
||||
"DiscardOldFileChange": "放弃旧文件变更",
|
||||
"SquashCommitDown": "向下压缩提交",
|
||||
"FixupCommit": "修正提交",
|
||||
"RewordCommit": "改写提交",
|
||||
"DropCommit": "删除提交",
|
||||
"EditCommit": "编辑提交",
|
||||
"AmendCommit": "修改提交",
|
||||
"AmendCommit": "提交修补",
|
||||
"ResetCommitAuthor": "重设作者",
|
||||
"SetCommitAuthor": "设置作者",
|
||||
"AddCommitCoAuthor": "添加其他的提交作者",
|
||||
"RevertCommit": "还原提交",
|
||||
"CreateFixupCommit": "创建修正提交",
|
||||
"SquashAllAboveFixupCommits": "压缩以上所有的修正提交",
|
||||
"MoveCommitUp": "上移提交",
|
||||
"MoveCommitDown": "下移提交",
|
||||
"CopyCommitMessageToClipboard": "将提交消息复制到剪贴板",
|
||||
"CopyCommitSubjectToClipboard": "复制提交主题到剪贴板",
|
||||
"CopyCommitDiffToClipboard": "复制提交差异到剪贴板",
|
||||
"CopyCommitHashToClipboard": "复制完整的提交哈希到剪贴板",
|
||||
"CopyCommitURLToClipboard": "复制提交URL到剪贴板",
|
||||
"CopyCommitAuthorToClipboard": "复制提交作者到剪贴板",
|
||||
"CopyCommitAttributeToClipboard": "复制到剪贴板",
|
||||
"CopyPatchToClipboard": "复制路径到剪贴板",
|
||||
"CustomCommand": "自定义命令",
|
||||
"DiscardAllChangesInDirectory": "丢弃目录中的所有更改",
|
||||
"DiscardUnstagedChangesInDirectory": "丢弃目录中未暂存的更改",
|
||||
"DiscardAllChangesInFile": "丢弃文件中的所有更改",
|
||||
"DiscardAllUnstagedChangesInFile": "丢弃文件中所有未暂存的更改",
|
||||
"DiscardAllChangesInDirectory": "丢弃目录中的所有变更",
|
||||
"DiscardUnstagedChangesInDirectory": "丢弃目录中未暂存的变更",
|
||||
"DiscardAllChangesInFile": "丢弃文件中的所有变更",
|
||||
"DiscardAllUnstagedChangesInFile": "丢弃文件中所有未暂存的变更",
|
||||
"StageFile": "暂存文件",
|
||||
"StageResolvedFiles": "合并冲突已解决的已暂存文件",
|
||||
"UnstageFile": "取消暂存文件",
|
||||
"UnstageAllFiles": "取消暂存所有文件",
|
||||
"StageAllFiles": "暂存所有文件",
|
||||
"IgnoreExcludeFile": "忽略文件",
|
||||
"Commit": "提交 (Commit)",
|
||||
"IgnoreFileErr": "无法忽略 .gitignore",
|
||||
"ExcludeFile": "排除文件",
|
||||
"ExcludeGitIgnoreErr": "无法排除.gitignore",
|
||||
"Commit": "提交(Commit)",
|
||||
"EditFile": "编辑文件",
|
||||
"Push": "推送 (Push)",
|
||||
"Pull": "拉取 (Pull)",
|
||||
"Push": "推送(Push)",
|
||||
"Pull": "拉取(Pull)",
|
||||
"OpenFile": "打开文件",
|
||||
"StashAllChanges": "贮藏所有更改",
|
||||
"StashStagedChanges": "贮藏暂存的更改",
|
||||
"StashAllChanges": "贮藏所有变更",
|
||||
"StashAllChangesKeepIndex": "贮藏所有更改并保持索引",
|
||||
"StashStagedChanges": "贮藏暂存的变更",
|
||||
"StashUnstagedChanges": "贮藏所有未暂存更改",
|
||||
"StashIncludeUntrackedChanges": "贮藏所有更改包括未跟踪的文件",
|
||||
"GitFlowFinish": "git flow 结果",
|
||||
"GitFlowStart": "git flow 开始",
|
||||
"CopyToClipboard": "复制到剪贴板",
|
||||
@@ -455,7 +855,8 @@
|
||||
"RemoveRemote": "移除远程",
|
||||
"UpdateRemote": "更新远程",
|
||||
"ApplyPatch": "应用补丁",
|
||||
"Stash": "贮藏 (Stash)",
|
||||
"Stash": "贮藏(Stash)",
|
||||
"RenameStash": "重命名贮藏",
|
||||
"RemoveSubmodule": "删除子模块",
|
||||
"ResetSubmodule": "重置子模块",
|
||||
"AddSubmodule": "添加子模块",
|
||||
@@ -467,36 +868,64 @@
|
||||
"UpdateSubmodule": "更新子模块",
|
||||
"CreateLightweightTag": "创建轻量标签",
|
||||
"CreateAnnotatedTag": "创建附注标签",
|
||||
"DeleteLocalTag": "删除本地标签",
|
||||
"DeleteRemoteTag": "删除远程标签",
|
||||
"PushTag": "推送标签",
|
||||
"NukeWorkingTree": "Nuke 工作树",
|
||||
"DiscardUnstagedFileChanges": "放弃未暂存的文件更改",
|
||||
"DiscardUnstagedFileChanges": "放弃未暂存的文件变更",
|
||||
"RemoveUntrackedFiles": "删除未跟踪的文件",
|
||||
"RemoveStagedFiles": "移除贮藏文件",
|
||||
"SoftReset": "软重置",
|
||||
"MixedReset": "混合重置",
|
||||
"HardReset": "硬重置",
|
||||
"Undo": "撤销",
|
||||
"Redo": "重做",
|
||||
"CopyPullRequestURL": "复制拉取请求 URL",
|
||||
"OpenDiffTool": "打开差异比较工具",
|
||||
"OpenMergeTool": "打开合并工具",
|
||||
"OpenCommitInBrowser": "在浏览器中打开提交",
|
||||
"OpenPullRequest": "在浏览器中打开拉取请求",
|
||||
"StartBisect": "开始二分查找 (Bisect)",
|
||||
"StartBisect": "开始二分查找(Bisect)",
|
||||
"ResetBisect": "重置二分查找",
|
||||
"BisectSkip": "二分查找跳过",
|
||||
"BisectMark": "二分查找标记"
|
||||
"BisectMark": "二分查找标记",
|
||||
"RemoveWorktree": "移除工作区",
|
||||
"AddWorktree": "添加工作区"
|
||||
},
|
||||
"Bisect": {
|
||||
"MarkStart": "将 %s 标记为 %s (start bisect)",
|
||||
"ResetTitle": "重置 'git bisect'",
|
||||
"ResetPrompt": "您确定要重置 'git bisect' 吗?",
|
||||
"ResetOption": "重置二分查找",
|
||||
"ChooseTerms": "二选一",
|
||||
"OldTermPrompt": "旧/好的提交:",
|
||||
"NewTermPrompt": "新/坏的提交:",
|
||||
"BisectMenuTitle": "二分查找",
|
||||
"Mark": "将 %s 标记为 %s",
|
||||
"SkipCurrent": "跳过 %s",
|
||||
"SkipSelected": "跳过所选提交(%s)",
|
||||
"CompleteTitle": "二分查找完成",
|
||||
"CompletePrompt": "二分查找完成!以下提交引入了此变更:\n\n%s\n\n您现在要重置 'git bisect' 吗?",
|
||||
"CompletePromptIndeterminate": "二分查找完成!一些提交被跳过了,所以下列提交中的任何一个都可能引入了此变更:\n\n%s\n\n您现在要重置 'git bisect' 吗?"
|
||||
"CompletePromptIndeterminate": "二分查找完成!一些提交被跳过了,所以下列提交中的任何一个都可能引入了此变更:\n\n%s\n\n您现在要重置 'git bisect' 吗?",
|
||||
"Bisecting": "二分查找中"
|
||||
},
|
||||
"Log": {},
|
||||
"BreakingChangesByVersion": {}
|
||||
"Log": {
|
||||
"EditRebase": "开始基于 '{{.ref}}' 进行交互式变基",
|
||||
"MoveCommitUp": "向下移动 TODO: '{{.shortHash}}'",
|
||||
"MoveCommitDown": "向上移动 TODO: '{{.shortHash}}'",
|
||||
"CherryPickCommits": "拣选提交:\n'{{.commitLines}}'",
|
||||
"HandleUndo": "撤销最后一次的冲突解决方案",
|
||||
"HandleMidRebaseCommand": "将提交 {{.shortHash}} 的变基操作更新为 '{{.action}}'",
|
||||
"RemoveFile": "正在删除路径 '{{.path}}'",
|
||||
"CopyToClipboard": "正在复制 '{{.str}}' 到剪贴板",
|
||||
"Remove": "删除 '{{.filename}}'",
|
||||
"CreateFileWithContent": "正在创建文件 '{{.path}}'",
|
||||
"AppendingLineToFile": "将 '{{.line}}' 附加到文件 '{{.filename}}'",
|
||||
"EditRebaseFromBaseCommit": "开始从'{{.baseCommit}}'进行交互式变基到'{{.targetBranchName}}‘"
|
||||
},
|
||||
"BreakingChangesTitle": "重大变化",
|
||||
"BreakingChangesMessage": "您正在更新到 lazygit 的新版本,其中含有中断的更改。请阅读下面的说明,并在必要时更新您的配置。\n欲了解更多信息,请参阅 <https://github.com/jesseduffield/lazygit/releases> 的完整版本说明。",
|
||||
"BreakingChangesByVersion": {
|
||||
"0.41.0": "- 当您按“g”调出 git 重置菜单时,“mixed”选项现在是第一个也是默认选项,而不是“soft”。这是因为“mixed”是最常用的选项。\n- 提交消息面板现在默认自动硬换行(即,当您到达页边距时,它会添加换行符)。您可以像这样调整配置:\n\ngit:\n commit:\n autoWrapCommitMessage: true\n autoWrapWidth: 72\n\n- “v”键已在暂存视图中用于启动范围选择,但现在您可以使用它在任何视图中启动范围选择。不幸的是,这与粘贴提交(cherry-pick)的“v”键绑定冲突,因此现在粘贴提交是通过“shift+V”完成的,为了一致性,复制提交现在是通过“shift+C”而不是“c”。请注意,“v”键绑定只是启动范围选择的一种方法:您可以使用 shift+向上/向下箭头。因此,如果您想配置cherry-pick键绑定以获得旧行为,请在配置中设置以下内容:\n\nkeybinding:\n universal:\n toggleRangeSelect: <something other than v>\n commits:\n cherryPickCopy: 'c'\n pasteCommits: 'v'\n\n- 使用“shift-S”压缩修复现在会弹出一个菜单,默认选项是压缩分支中的所有修复提交。仅压缩所选提交之上的修复提交的原始行为仍然可以作为该菜单中的第二个选项使用。\n- Push/pull/fetch 加载状态现在显示在分支上,而不是在弹出窗口中。这允许您例如并行获取多个分支并查看每个分支的状态。\n- 提交视图中的 git 日志图现在始终默认显示(以前仅在视图最大化时显示)。如果你发现这太冗余了,你可以通过 ctrl+L -> 'Show git graph' -> 'when maximized' 将其改回来\n- 在远程分支上按空格用于显示输入新本地分支名称的提示,以从远程分支检出。现在它只是直接检查远程分支,让您在同名的新本地分支或分离的头之间进行选择。旧的行为仍然可以通过“n”键绑定使用。\n- 默认情况下,过滤(例如按“/”时)不太模糊;它现在只匹配子字符串。多个子字符串可以通过用空格分隔来匹配。如果您想恢复到旧的行为,请在配置中设置以下内容:\n\ngui:\n filterMode: 'fuzzy'\n\t "
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
"MainTitle": "主要",
|
||||
"StagingTitle": "主面板(預存)",
|
||||
"MergingTitle": "主面板(合併)",
|
||||
"SquashMergeUncommittedTitle": "壓縮合併但不提交",
|
||||
"SquashMergeCommittedTitle": "壓縮合併並提交",
|
||||
"NormalTitle": "主面板(一般)",
|
||||
"LogTitle": "版本記錄",
|
||||
"CommitSummary": "提交摘要",
|
||||
@@ -21,6 +23,7 @@
|
||||
"CredentialsPIN": "SSH 金鑰 PIN 碼",
|
||||
"PassUnameWrong": "密碼、密語或使用者名稱錯誤",
|
||||
"Commit": "提交變更",
|
||||
"CommitTooltip": "提交暫存區變更",
|
||||
"AmendLastCommit": "修改上次提交",
|
||||
"AmendLastCommitTitle": "修改上次提交",
|
||||
"SureToAmend": "是否確定要修改上次提交?之後你可以從提交面板中再次更改此次提交的訊息。",
|
||||
@@ -33,17 +36,32 @@
|
||||
"Stage": "切換預存",
|
||||
"ToggleStagedAll": "全部預存/取消預存",
|
||||
"ToggleTreeView": "顯示檔案樹狀視圖",
|
||||
"OpenMergeTool": "開啟外部合併工具 (git mergetool)",
|
||||
"OpenDiffTool": "開啟外部差異工具 (git difftool)",
|
||||
"OpenMergeTool": "開啟外部合併工具",
|
||||
"OpenMergeToolTooltip": "執行 `git mergetool`。",
|
||||
"Refresh": "重新整理",
|
||||
"Push": "推送",
|
||||
"Pull": "拉取",
|
||||
"PushTooltip": "推送到遠端。如果沒有設定遠端,會開啟設定視窗。",
|
||||
"PullTooltip": "從遠端同步當前分支。如果沒有設定遠端,會開啟設定視窗。",
|
||||
"Scroll": "捲動",
|
||||
"FileFilter": "篩選檔案 (預存/未預存)",
|
||||
"CopyToClipboardMenu": "複製到剪貼簿",
|
||||
"CopyFileName": "檔案名稱",
|
||||
"CopyFilePath": "路徑",
|
||||
"CopyFileDiffTooltip": "如果有已預存的項目,此指令只考慮它們。否則,它將考慮所有未暫存的項目。",
|
||||
"CopySelectedDiff": "所選檔案的差異",
|
||||
"CopyAllFilesDiff": "所有檔案的差異",
|
||||
"FileNameCopiedToast": "檔案名稱已複製",
|
||||
"FilePathCopiedToast": "檔案路徑已複製",
|
||||
"FileDiffCopiedToast": "已複製檔案差異",
|
||||
"AllFilesDiffCopiedToast": "已複製所有檔案差異",
|
||||
"FilterStagedFiles": "僅顯示預存的檔案",
|
||||
"FilterUnstagedFiles": "僅顯示未預存的檔案",
|
||||
"ResetFilter": "重設篩選",
|
||||
"MergeConflictsTitle": "合併衝突",
|
||||
"Checkout": "檢出",
|
||||
"CheckoutTooltip": "檢出選定的項目。",
|
||||
"NoChangedFiles": "沒有變更的檔案",
|
||||
"SoftReset": "軟重設",
|
||||
"AlreadyCheckedOutBranch": "你已經檢出這個分支了",
|
||||
@@ -52,12 +70,18 @@
|
||||
"BranchName": "分支名稱",
|
||||
"NewBranchNameBranchOff": "新的分支名稱 (根據 '{{.branchName}}' 分支創建)",
|
||||
"CantDeleteCheckOutBranch": "無法刪除已檢出的分支!",
|
||||
"DeleteRemoteBranchPrompt": "確定要刪除遠端 {{.upstream}} 的標籤 '{{.selectedBranchName}}'?",
|
||||
"ForceDeleteBranchMessage": "'{{.selectedBranchName}}' 分支尚未完全合併。是否刪除?",
|
||||
"RebaseBranch": "將已檢出的分支變基至此分支",
|
||||
"CantRebaseOntoSelf": "無法將分支變基至自己",
|
||||
"CantMergeBranchIntoItself": "無法將一個分支合併至自己",
|
||||
"ForceCheckout": "強制檢出",
|
||||
"CheckoutByName": "根據名稱檢出",
|
||||
"RemoteBranchCheckoutTitle": "檢出 {{.branchName}}",
|
||||
"CheckoutTypeNewBranch": "新本地分支",
|
||||
"CheckoutTypeNewBranchTooltip": "將遠端分支檢出為追蹤它的本地分支。",
|
||||
"CheckoutTypeDetachedHead": "分離 HEAD",
|
||||
"CheckoutTypeDetachedHeadTooltip": "將遠端分支檢出為分離的 HEAD,在只想測試但不動工時很實用。您稍後仍能根據它建立一個本地分支。",
|
||||
"NewBranch": "新分支",
|
||||
"NoBranchesThisRepo": "這個版本庫中沒有分支",
|
||||
"CommitWithoutMessageErr": "沒有提交訊息,無法提交",
|
||||
@@ -71,15 +95,22 @@
|
||||
"SureSquashThisCommit": "是否要把這個提交壓縮到下面的提交中?",
|
||||
"Squash": "壓縮 (Squash)",
|
||||
"PickCommitTooltip": "挑選提交 (於變基過程中)",
|
||||
"Pick": "挑選",
|
||||
"Edit": "編輯",
|
||||
"RevertCommit": "還原提交",
|
||||
"Revert": "還原",
|
||||
"Reword": "改寫提交",
|
||||
"CommitRewordTooltip": "改寫選中的提交訊息",
|
||||
"DropCommit": "刪除提交",
|
||||
"MoveDownCommit": "向下移動提交",
|
||||
"MoveUpCommit": "向上移動提交",
|
||||
"EditCommit": "編輯(開始互動變基)",
|
||||
"EditCommitTooltip": "編輯提交",
|
||||
"AmendCommitTooltip": "使用已預存的更改修正提交",
|
||||
"Amend": "修改",
|
||||
"ResetAuthor": "重設作者",
|
||||
"SetAuthor": "設定作者",
|
||||
"AddCoAuthor": "添加合作者",
|
||||
"AmendCommitAttribute": "設定/重設提交作者",
|
||||
"SetAuthorPromptTitle": "設定作者(格式:「姓名 <電子郵件>」)",
|
||||
"SureResetCommitAuthor": "為了符合已配置的使用者,此作者的提交欄位以及時間戳將被更新。是否繼續?",
|
||||
@@ -131,15 +162,19 @@
|
||||
"ConfirmQuitDuringUpdate": "正在進行更新,是否結束?",
|
||||
"MergeToolTitle": "合併工具",
|
||||
"MergeToolPrompt": "是否開啟 'git mergetool'?",
|
||||
"IntroPopupMessage": "\n感謝使用 lazygit!這裡有一些資源可供參考:\n\n 1) 📺lazygit 教學📺:\n https://youtu.be/CPLdltN7wgE\n\n 2) 📣釋出說明📣:\n https://github.com/jesseduffield/lazygit/releases\n\n 3) 💖如果你想要貢獻一份心力你可以💖:\n 改進 lazygit 原始碼:https://github.com/jesseduffield/lazygit\n 按右下角的捐款斗內我們\n 或單存添加 lazygit 到你的 star 清單內以增加曝光度都能大力的幫助我們!\n",
|
||||
"IntroPopupMessage": "\n感謝使用 lazygit!這裡有一些資源可供參考:\n\n 1) 📺lazygit 教學📺:\n https://youtu.be/CPLdltN7wgE\n\n 2) 📣發佈說明📣:\n https://github.com/jesseduffield/lazygit/releases\n\n 3) 💖如果你想要貢獻一份心力你可以💖:\n 改進 lazygit 原始碼:https://github.com/jesseduffield/lazygit\n 按右下角的捐款斗內我們\n 或單純添加 lazygit 到你的 star 清單內以增加曝光度都能大力的幫助我們!\n",
|
||||
"DeprecatedEditConfigWarning": "\n### Deprecated config warning ###\n\n以下設定已被取代並將於未來版本中刪除:\n{{configs}}\n\n編輯器設定教學:\n\n https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#configuring-file-editing\n\n",
|
||||
"GitconfigParseErr": "Gogit 無法解析你的 gitconfig 檔案,因為存在未引用的 '\\' 字符,刪除它們應該可以解決這個問題。",
|
||||
"EditFile": "編輯檔案",
|
||||
"EditFileTooltip": "使用外部編輯器開啟",
|
||||
"OpenFile": "開啟檔案",
|
||||
"OpenFileTooltip": "使用預設軟體開啟",
|
||||
"OpenInEditor": "在編輯器中開啟",
|
||||
"IgnoreFile": "添加到 .gitignore",
|
||||
"ExcludeFile": "添加到 .git/info/exclude",
|
||||
"RefreshFiles": "重新整理檔案",
|
||||
"Merge": "合併到當前檢出的分支",
|
||||
"RegularMerge": "一般合併",
|
||||
"ConfirmQuit": "是否結束?",
|
||||
"SwitchRepo": "切換到最近使用的版本庫",
|
||||
"AllBranchesLogGraph": "顯示所有分支日誌",
|
||||
@@ -147,6 +182,7 @@
|
||||
"CopyPullRequestURL": "複製拉取請求的 URL 到剪貼板",
|
||||
"NoBranchOnRemote": "這個分支在遠端不存在。需要先將其推送至遠端。",
|
||||
"Fetch": "擷取",
|
||||
"FetchTooltip": "同步遠端異動",
|
||||
"NoAutomaticGitFetchTitle": "手動 git 擷取",
|
||||
"NoAutomaticGitFetchBody": "lazygit 無法在私有庫使用 \"git 擷取\";在檔案面板中使用 'f' 手動執行 \"git 擷取\"",
|
||||
"FileEnter": "選擇檔案中的單個程式碼塊/行,或展開/折疊目錄",
|
||||
@@ -159,11 +195,15 @@
|
||||
"ToggleStagingView": "切換至另一個面板 (已預存/未預存更改)",
|
||||
"ReturnToFilesPanel": "返回檔案面板",
|
||||
"FastForward": "從上游快進此分支",
|
||||
"FastForwardTooltip": "從遠端快進所選的分支",
|
||||
"FastForwarding": "的擷取和快進中",
|
||||
"FoundConflictsTitle": "自動合併失敗",
|
||||
"ViewConflictsMenuItem": "檢視衝突",
|
||||
"AbortMenuItem": "關於%s",
|
||||
"PickHunk": "挑選程式碼片段",
|
||||
"PickAllHunks": "挑選所有程式碼片段",
|
||||
"ViewMergeRebaseOptions": "查看合併/變基選項",
|
||||
"ViewRebaseOptions": "查看合併/變基選項",
|
||||
"NotMergingOrRebasing": "你當前既不在變基也不在合併中",
|
||||
"AlreadyRebasing": "無法在變基期間執行此操作",
|
||||
"RecentRepos": "最近的版本庫",
|
||||
@@ -188,9 +228,10 @@
|
||||
"SimpleRebase": "簡單變基 變基至 '{{.ref}}'",
|
||||
"InteractiveRebase": "互動變基 變基至 '{{.ref}}'",
|
||||
"InteractiveRebaseTooltip": "開始一個互動變基,以中斷開始,這樣你可以在繼續之前更新TODO提交",
|
||||
"FwdNoUpstream": "無法快進無上游分支",
|
||||
"FwdNoUpstream": "無法快進無遠端的分支 ",
|
||||
"FwdNoLocalUpstream": "無法快進尚未在本地註冊的遠端分支",
|
||||
"FwdCommitsToPush": "無法快進帶有尚未推送的提交的分支",
|
||||
"PullRequestNoUpstream": "無法對沒有遠端的分支拉取",
|
||||
"ErrorOccurred": "發生錯誤!請在此詢問錯誤:",
|
||||
"NoRoom": "無足夠的空間",
|
||||
"YouAreHere": "你在這",
|
||||
@@ -238,9 +279,9 @@
|
||||
"CommittingStatus": "提交中",
|
||||
"RevertingStatus": "還原中",
|
||||
"CommitFiles": "提交檔案",
|
||||
"SubCommitsDynamicTitle": "提交 (共 %s項)",
|
||||
"CommitFilesDynamicTitle": "差異檔案 (共 %s項)",
|
||||
"RemoteBranchesDynamicTitle": "遠端分支 (共 %s項)",
|
||||
"SubCommitsDynamicTitle": "提交(%s)",
|
||||
"CommitFilesDynamicTitle": "差異檔案(%s)",
|
||||
"RemoteBranchesDynamicTitle": "遠端分支(%s)",
|
||||
"ViewItemFiles": "檢視所選項目的檔案",
|
||||
"CommitFilesTitle": "提交檔案",
|
||||
"CheckoutCommitFileTooltip": "檢出檔案",
|
||||
@@ -255,6 +296,9 @@
|
||||
"AutoStashTitle": "是否自動收藏?",
|
||||
"AutoStashPrompt": "必須收藏並拾起變更才得以繼續操作。是否自動執行?(Enter/Esc)",
|
||||
"StashPrefix": "自動收藏 ",
|
||||
"Discard": "捨棄",
|
||||
"DiscardChangesTitle": "捨棄變更",
|
||||
"DiscardFileChangesTooltip": "檢視選中變動進行捨棄復原",
|
||||
"Cancel": "取消",
|
||||
"DiscardAllChanges": "刪除所有變更",
|
||||
"DiscardUnstagedChanges": "刪除未預存變更",
|
||||
@@ -263,6 +307,8 @@
|
||||
"DiscardUntrackedFiles": "刪除未追蹤檔案",
|
||||
"DiscardStagedChanges": "刪除已預存變更",
|
||||
"HardReset": "強制重設",
|
||||
"Delete": "刪除",
|
||||
"Reset": "重設",
|
||||
"ViewResetOptions": "檢視重設選項",
|
||||
"CreateFixupCommit": "建立修復提交",
|
||||
"CreateFixupCommitTooltip": "為此提交建立修復提交",
|
||||
@@ -275,6 +321,7 @@
|
||||
"ResetTo": "重設至",
|
||||
"PressEnterToReturn": "按 Enter 返回到 lazygit",
|
||||
"ViewStashOptions": "檢視收藏選項",
|
||||
"Stash": "收藏",
|
||||
"StashAllChanges": "收藏所有變更",
|
||||
"StashStagedChanges": "收藏已預存變更",
|
||||
"StashAllChangesKeepIndex": "收藏所有變更並保留預存區",
|
||||
@@ -297,8 +344,8 @@
|
||||
"NoPatchError": "尚未建立補丁。要開始建立補丁,請在提交檔案上使用空格或輸入以添加特定行",
|
||||
"EnterCommitFile": "輸入檔案以將選定的行添加至補丁(或切換目錄折疊)",
|
||||
"ExitCustomPatchBuilder": "退出自訂補丁建立器",
|
||||
"EnterUpstream": "輸入上游為 '<remote> <branchname>'",
|
||||
"InvalidUpstream": "無效的上游。必須符合 '<remote> <branchname>' 的格式",
|
||||
"EnterUpstream": "輸入遠端為 '<remote> <branchname>'",
|
||||
"InvalidUpstream": "無效的遠端分支名稱。必須符合 '<remote> <branchname>' 的格式",
|
||||
"ReturnToRemotesList": "返回遠端列表",
|
||||
"NewRemote": "新增遠端",
|
||||
"NewRemoteName": "新遠端名稱:",
|
||||
@@ -309,10 +356,18 @@
|
||||
"RemoveRemotePrompt": "你確定要移除遠端?",
|
||||
"DeleteRemoteBranch": "刪除遠端分支",
|
||||
"DeleteRemoteBranchMessage": "你確定要刪除遠端分支?",
|
||||
"SetAsUpstreamTooltip": "將此分支設為當前分支之上游",
|
||||
"SetUpstream": "設定所選分支之上游",
|
||||
"UnsetUpstream": "取消設定選定分支之上游",
|
||||
"SetUpstreamTitle": "設定上游分支",
|
||||
"SetAsUpstream": "設置為遠端",
|
||||
"SetAsUpstreamTooltip": "將此分支設為當前分支之遠端",
|
||||
"SetUpstream": "設定選定分支的遠端分支",
|
||||
"UnsetUpstream": "重置選定分支的遠端",
|
||||
"ViewDivergenceFromUpstream": "檢視與遠端的差異",
|
||||
"DivergenceSectionHeaderLocal": "本地",
|
||||
"ViewUpstreamResetOptions": "重設當前分支進 {{.upstream}}",
|
||||
"ViewUpstreamResetOptionsTooltip": "查看重設當前分支進 {{upstream}} 的選項。注意:此動作不會重置所選的遠端,而是將當前分支重置到遠端",
|
||||
"ViewUpstreamRebaseOptions": "將當前分支變基到 {{.upstream}}",
|
||||
"ViewUpstreamRebaseOptionsTooltip": "查看變基當前分支到 {{upstream}} 的選項。注意:此動作不會變基所選的遠端,而是將當前分支變基到遠端",
|
||||
"UpstreamGenericName": "選定分支的選端",
|
||||
"SetUpstreamTitle": "設定遠端分支",
|
||||
"SetUpstreamMessage": "你確定要將 '{{. selected}}' 設為 '{{.checkedOut}}' 的上游分支?",
|
||||
"EditRemoteTooltip": "編輯遠端",
|
||||
"TagCommit": "打標籤到提交",
|
||||
@@ -321,6 +376,8 @@
|
||||
"TagMessageTitle": "標籤訊息",
|
||||
"LightweightTag": "輕量標籤",
|
||||
"AnnotatedTag": "附註標籤",
|
||||
"DeleteLocalTag": "刪除本地標籤",
|
||||
"DeleteRemoteTagPrompt": "確定要刪除遠端 {{.upstream}} 的標籤 '{{.tagName}}'?",
|
||||
"PushTagTitle": "推送標籤 '{{.tagName}}' 至遠端:",
|
||||
"PushTag": "推送標籤",
|
||||
"NewTag": "建立標籤",
|
||||
@@ -334,7 +391,7 @@
|
||||
"IgnoreTracked": "忽略已追蹤檔案",
|
||||
"ExcludeTracked": "排除已追蹤檔案",
|
||||
"IgnoreTrackedPrompt": "你確定要忽略一個已追蹤的檔案?",
|
||||
"ViewResetToUpstreamOptions": "檢視上游重設選項",
|
||||
"ViewResetToUpstreamOptions": "檢視遠端重設選項",
|
||||
"NextScreenMode": "下一個螢幕模式(常規/半螢幕/全螢幕)",
|
||||
"PrevScreenMode": "上一個螢幕模式",
|
||||
"StartSearch": "搜尋",
|
||||
@@ -342,11 +399,15 @@
|
||||
"Panel": "面板",
|
||||
"Keybindings": "鍵盤快捷鍵",
|
||||
"KeybindingsLegend": "說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B",
|
||||
"KeybindingsMenuSectionLocal": "本地",
|
||||
"KeybindingsMenuSectionGlobal": "全域",
|
||||
"RenameBranch": "重新命名分支",
|
||||
"BranchUpstreamOptionsTitle": "上游分支設定",
|
||||
"ViewBranchUpstreamOptions": "檢視上游設定",
|
||||
"ViewBranchUpstreamOptionsTooltip": "檢視有關上游分支的設定(例如重設至上游)",
|
||||
"UpstreamNotSetError": "目標分支沒有上游分支(或其上游分支未儲存於本地)",
|
||||
"Upstream": "遠端",
|
||||
"UpstreamTooltip": "查看所選分支的遠端設定(例如設置/重置遠端)",
|
||||
"BranchUpstreamOptionsTitle": "上游遠端設定",
|
||||
"ViewBranchUpstreamOptions": "檢視遠端設定",
|
||||
"ViewBranchUpstreamOptionsTooltip": "檢視有關遠端分支的設定(例如重設至遠端)",
|
||||
"UpstreamNotSetError": "目標分支沒有遠端對應分支(或其遠端分支未儲存於本地)",
|
||||
"NewGitFlowBranchPrompt": "{{.branchType}} 名稱:",
|
||||
"RenameBranchWarning": "此分支正在追蹤遠端分支。此操作僅會重新命名本地分支名稱,而不是遠端分支的名稱。是否繼續?",
|
||||
"OpenKeybindingsMenu": "開啟選單",
|
||||
@@ -475,6 +536,11 @@
|
||||
"LogMenuTitle": "提交記錄選項",
|
||||
"ToggleShowGitGraphAll": "切換顯示整個 git 圖表(將 `--all` 標誌傳遞給 `git log`)",
|
||||
"ShowGitGraph": "顯示 git 圖表",
|
||||
"SortOrder": "排序規則",
|
||||
"SortAlphabetical": "依字母",
|
||||
"SortByDate": "依時間",
|
||||
"SortByRecency": "依最近使用",
|
||||
"SortBasedOnReflog": "(依據歷史記錄)",
|
||||
"SortCommits": "提交排序順序",
|
||||
"CantChangeContextSizeError": "在製作補丁期間無法更改上下文大小,因為當發布功能時我們太懒了以至於沒有支援它。如果你真的需要它,請告訴我們!",
|
||||
"OpenCommitInBrowser": "在瀏覽器中開啟提交",
|
||||
@@ -484,8 +550,8 @@
|
||||
"RewordInEditorPrompt": "是否在編輯器中改寫此提交?",
|
||||
"CheckoutPrompt": "是否檢出 '%s' ?",
|
||||
"HardResetAutostashPrompt": "是否強制重設為 '%s' ?如果需要會進行自動存儲。",
|
||||
"UpstreamGone": "(上游已經不存在)",
|
||||
"NukeDescription": "如果你想讓所有工作樹上的變更消失,這就是要做的方式。如果有未提交的子模組變更,它將把這些變更藏在子模組中。",
|
||||
"UpstreamGone": "(遠端已經不存在)",
|
||||
"NukeDescription": "如果你想讓所有工作樹上的變更消失,這就是正確的選項。如果有未提交的子模組變更,它們將被收藏在子模組中。",
|
||||
"DiscardStagedChangesDescription": "這將創建一個新的存儲條目,其中只包含預存檔案,然後如果存儲條目不需要,將其刪除,因此工作樹僅保留未預存的變更。",
|
||||
"EmptyOutput": "<空輸出>",
|
||||
"Patch": "補丁",
|
||||
@@ -547,12 +613,14 @@
|
||||
"PleaseGoToURL": "請開啟 URL:{{.url}}",
|
||||
"NoCopiedCommits": "未複製提交",
|
||||
"DisabledMenuItemPrefix": "已停用:",
|
||||
"QuickStartInteractiveRebase": "開始互動變基",
|
||||
"ToggleRangeSelect": "切換拖曳選擇",
|
||||
"Actions": {
|
||||
"CheckoutCommit": "檢出提交",
|
||||
"CheckoutTag": "檢出標籤",
|
||||
"CheckoutBranch": "檢出分支",
|
||||
"ForceCheckoutBranch": "強制檢出分支",
|
||||
"DeleteLocalBranch": "刪除本地分支",
|
||||
"DeleteBranch": "刪除分支",
|
||||
"Merge": "合併",
|
||||
"RebaseBranch": "變基分支",
|
||||
@@ -615,7 +683,7 @@
|
||||
"MovePatchIntoIndex": "將補丁移動到索引中",
|
||||
"MovePatchIntoNewCommit": "將補丁移動到新提交中",
|
||||
"DeleteRemoteBranch": "刪除遠端分支",
|
||||
"SetBranchUpstream": "設置分支上游",
|
||||
"SetBranchUpstream": "設置遠端分支",
|
||||
"AddRemote": "添加遠端",
|
||||
"RemoveRemote": "移除遠端",
|
||||
"UpdateRemote": "更新遠端",
|
||||
@@ -633,12 +701,13 @@
|
||||
"UpdateSubmodule": "更新子模塊",
|
||||
"CreateLightweightTag": "建立輕量標籤",
|
||||
"CreateAnnotatedTag": "建立附註標籤",
|
||||
"DeleteLocalTag": "刪除本地標籤",
|
||||
"PushTag": "推送標籤",
|
||||
"NukeWorkingTree": "清空工作樹",
|
||||
"DiscardUnstagedFileChanges": "放棄未預存的檔案更改",
|
||||
"RemoveUntrackedFiles": "移除未追蹤的檔案",
|
||||
"RemoveStagedFiles": "移除已預存的檔案",
|
||||
"SoftReset": "軟重設",
|
||||
"SoftReset": "軟重設(保留變動)",
|
||||
"MixedReset": "混合重設",
|
||||
"HardReset": "強制重設",
|
||||
"Undo": "復原",
|
||||
@@ -665,6 +734,8 @@
|
||||
"CompletePromptIndeterminate": "二分查找完成!有一些提交被跳過,因此以下任何提交皆可能引進更改:\n\n%s\n\n是否重設 `git bisect`?",
|
||||
"Bisecting": "二分查找中"
|
||||
},
|
||||
"Log": {},
|
||||
"Log": {
|
||||
"CopyToClipboard": "{{.str}} 已複製"
|
||||
},
|
||||
"BreakingChangesByVersion": {}
|
||||
}
|
||||
|
||||
@@ -15,27 +15,52 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
CloneIntoRemote("origin").
|
||||
EmptyCommit("blah").
|
||||
NewBranch("branch-one").
|
||||
EmptyCommit("on branch-one 01").
|
||||
PushBranchAndSetUpstream("origin", "branch-one").
|
||||
EmptyCommit("on branch-one 02").
|
||||
Checkout("master").
|
||||
Merge("branch-one"). // branch-one is contained in master, so no delete confirmation
|
||||
NewBranch("branch-two").
|
||||
PushBranchAndSetUpstream("origin", "branch-two").
|
||||
EmptyCommit("deletion blocker").
|
||||
NewBranch("branch-three")
|
||||
EmptyCommit("on branch-two 01").
|
||||
PushBranchAndSetUpstream("origin", "branch-two"). // branch-two is contained in its own upstream, so no delete confirmation either
|
||||
NewBranchFrom("branch-three", "master").
|
||||
EmptyCommit("on branch-three 01").
|
||||
NewBranch("current-head"). // branch-three is contained in the current head, so no delete confirmation
|
||||
EmptyCommit("on current-head").
|
||||
NewBranchFrom("branch-four", "master").
|
||||
EmptyCommit("on branch-four 01").
|
||||
PushBranchAndSetUpstream("origin", "branch-four").
|
||||
EmptyCommit("on branch-four 02"). // branch-four is not contained in any of these, so we get a delete confirmation
|
||||
NewBranchFrom("branch-five", "master").
|
||||
EmptyCommit("on branch-five 01").
|
||||
PushBranchAndSetUpstream("origin", "branch-five"). // branch-five is contained in its own upstream
|
||||
NewBranchFrom("branch-six", "master").
|
||||
EmptyCommit("on branch-six 01").
|
||||
PushBranchAndSetUpstream("origin", "branch-six").
|
||||
EmptyCommit("on branch-six 02"). // branch-six is not contained in any of these, so we get a delete confirmation
|
||||
Checkout("current-head")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Lines(
|
||||
MatchesRegexp(`\*.*branch-three`).IsSelected(),
|
||||
MatchesRegexp(`branch-two`),
|
||||
MatchesRegexp(`branch-one`),
|
||||
MatchesRegexp(`master`),
|
||||
Contains("current-head").IsSelected(),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("branch-four ↑1"),
|
||||
Contains("branch-three"),
|
||||
Contains("branch-two ✓"),
|
||||
Contains("master"),
|
||||
Contains("branch-one ↑1"),
|
||||
).
|
||||
|
||||
// Deleting the current branch is not possible
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Tooltip(Contains("You cannot delete the checked out branch!")).
|
||||
Title(Equals("Delete branch 'branch-three'?")).
|
||||
Title(Equals("Delete branch 'current-head'?")).
|
||||
Select(Contains("Delete local branch")).
|
||||
Confirm().
|
||||
Tap(func() {
|
||||
@@ -43,7 +68,54 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
}).
|
||||
Cancel()
|
||||
}).
|
||||
SelectNextItem().
|
||||
|
||||
// Delete branch-four. This is the only branch that is not fully merged, so we get
|
||||
// a confirmation popup.
|
||||
NavigateToLine(Contains("branch-four")).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Delete branch 'branch-four'?")).
|
||||
Select(Contains("Delete local branch")).
|
||||
Confirm()
|
||||
t.ExpectPopup().
|
||||
Confirmation().
|
||||
Title(Equals("Force delete branch")).
|
||||
Content(Equals("'branch-four' is not fully merged. Are you sure you want to delete it?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("current-head"),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("branch-three").IsSelected(),
|
||||
Contains("branch-two ✓"),
|
||||
Contains("master"),
|
||||
Contains("branch-one ↑1"),
|
||||
).
|
||||
|
||||
// Delete branch-three. This branch is contained in the current head, so this just works
|
||||
// without any confirmation.
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Delete branch 'branch-three'?")).
|
||||
Select(Contains("Delete local branch")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("current-head"),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("branch-two ✓").IsSelected(),
|
||||
Contains("master"),
|
||||
Contains("branch-one ↑1"),
|
||||
).
|
||||
|
||||
// Delete branch-two. This branch is contained in its own upstream, so this just works
|
||||
// without any confirmation.
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
@@ -52,18 +124,16 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Select(Contains("Delete local branch")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Confirmation().
|
||||
Title(Equals("Force delete branch")).
|
||||
Content(Equals("'branch-two' is not fully merged. Are you sure you want to delete it?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
MatchesRegexp(`\*.*branch-three`),
|
||||
MatchesRegexp(`branch-one`).IsSelected(),
|
||||
MatchesRegexp(`master`),
|
||||
Contains("current-head"),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("master").IsSelected(),
|
||||
Contains("branch-one ↑1"),
|
||||
).
|
||||
|
||||
// Delete remote branch of branch-one. We only get the normal remote branch confirmation for this one.
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
@@ -87,7 +157,12 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().
|
||||
RemoteBranches().
|
||||
Lines(Equals("branch-two")).
|
||||
Lines(
|
||||
Equals("branch-five"),
|
||||
Equals("branch-four"),
|
||||
Equals("branch-six"),
|
||||
Equals("branch-two"),
|
||||
).
|
||||
Press(keys.Universal.Return)
|
||||
|
||||
t.Views().
|
||||
@@ -95,10 +170,15 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Focus()
|
||||
}).
|
||||
Lines(
|
||||
MatchesRegexp(`\*.*branch-three`),
|
||||
MatchesRegexp(`branch-one \(upstream gone\)`).IsSelected(),
|
||||
MatchesRegexp(`master`),
|
||||
Contains("current-head"),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("master"),
|
||||
Contains("branch-one (upstream gone)").IsSelected(),
|
||||
).
|
||||
|
||||
// Delete local branch of branch-one. Even though its upstream is gone, we don't get a confirmation
|
||||
// because it is contained in master.
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
@@ -108,8 +188,53 @@ var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
MatchesRegexp(`\*.*branch-three`),
|
||||
MatchesRegexp(`master`).IsSelected(),
|
||||
Contains("current-head"),
|
||||
Contains("branch-six ↑1"),
|
||||
Contains("branch-five ✓"),
|
||||
Contains("master").IsSelected(),
|
||||
).
|
||||
|
||||
// Delete both local and remote branch of branch-six. We get the force-delete warning because it is not fully merged.
|
||||
NavigateToLine(Contains("branch-six")).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Delete branch 'branch-six'?")).
|
||||
Select(Contains("Delete local and remote branch")).
|
||||
Confirm()
|
||||
t.ExpectPopup().
|
||||
Confirmation().
|
||||
Title(Equals("Delete local and remote branch")).
|
||||
Content(Contains("Are you sure you want to delete both 'branch-six' from your machine, and 'branch-six' from 'origin'?").
|
||||
Contains("'branch-six' is not fully merged. Are you sure you want to delete it?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("current-head"),
|
||||
Contains("branch-five ✓").IsSelected(),
|
||||
Contains("master"),
|
||||
).
|
||||
|
||||
// Delete both local and remote branch of branch-five. We get the same popups, but the confirmation
|
||||
// doesn't contain the force-delete warning.
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Delete branch 'branch-five'?")).
|
||||
Select(Contains("Delete local and remote branch")).
|
||||
Confirm()
|
||||
t.ExpectPopup().
|
||||
Confirmation().
|
||||
Title(Equals("Delete local and remote branch")).
|
||||
Content(Equals("Are you sure you want to delete both 'branch-five' from your machine, and 'branch-five' from 'origin'?").
|
||||
DoesNotContain("not fully merged")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("current-head"),
|
||||
Contains("master").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var DeleteRemoteBranchWithDifferentName = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Delete a remote branch that has a different name than the local branch",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.EmptyCommit("one")
|
||||
shell.CloneIntoRemote("origin")
|
||||
shell.NewBranch("mybranch-local")
|
||||
shell.PushBranchAndSetUpstream("origin", "mybranch-local:mybranch-remote")
|
||||
shell.Checkout("master")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("master").IsSelected(),
|
||||
Contains("mybranch-local ✓"),
|
||||
).
|
||||
SelectNextItem().
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Delete branch 'mybranch-local'?")).
|
||||
Select(Contains("Delete remote branch")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Confirmation().
|
||||
Title(Equals("Delete branch 'mybranch-remote'?")).
|
||||
Content(Equals("Are you sure you want to delete the remote branch 'mybranch-remote' from 'origin'?")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("master"),
|
||||
Contains("mybranch-local (upstream gone)").IsSelected(),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var ShowDivergenceFromUpstreamNoDivergence = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Show divergence from upstream when the divergence view is empty",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.EmptyCommit("commit1")
|
||||
shell.CloneIntoRemote("origin")
|
||||
shell.SetBranchUpstream("master", "origin/master")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Lines(Contains("master")).
|
||||
Press(keys.Branches.SetUpstream)
|
||||
|
||||
t.ExpectPopup().Menu().Title(Contains("Upstream")).Select(Contains("View divergence from upstream")).Confirm()
|
||||
|
||||
t.Views().SubCommits().
|
||||
IsFocused().
|
||||
Title(Contains("Commits (master <-> origin/master)")).
|
||||
Lines(
|
||||
Contains("--- Remote ---"),
|
||||
Contains("--- Local ---"),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -79,5 +79,32 @@ var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("one"),
|
||||
Contains("base"),
|
||||
)
|
||||
|
||||
// Even though the cherry-picking mode has been reset, it's still possible to paste the copied commits again:
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
NavigateToLine(Contains("master")).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("base").IsSelected(),
|
||||
).
|
||||
Press(keys.Commits.PasteCommits).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Cherry-pick")).
|
||||
Content(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?")).
|
||||
Confirm()
|
||||
}).
|
||||
Tap(func() {
|
||||
t.Views().Information().Content(DoesNotContain("commits copied"))
|
||||
}).
|
||||
Lines(
|
||||
Contains("four"),
|
||||
Contains("three"),
|
||||
Contains("base"),
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package commit
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
// We're emulating the clipboard by writing to a file called clipboard
|
||||
|
||||
var CopyAuthorToClipboard = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Copy a commit author name to the clipboard",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
// Include delimiters around the text so that we can assert on the entire content
|
||||
config.GetUserConfig().OS.CopyToClipboardCmd = "echo /{{text}}/ > clipboard"
|
||||
},
|
||||
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.SetAuthor("John Doe", "john@doe.com")
|
||||
shell.EmptyCommit("commit")
|
||||
},
|
||||
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("commit").IsSelected(),
|
||||
).
|
||||
Press(keys.Commits.CopyCommitAttributeToClipboard)
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Copy to clipboard")).
|
||||
Select(Contains("Commit author")).
|
||||
Confirm()
|
||||
|
||||
t.ExpectToast(Equals("Commit author copied to clipboard"))
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Press(keys.Files.RefreshFiles).
|
||||
Lines(
|
||||
Contains("clipboard").IsSelected(),
|
||||
)
|
||||
|
||||
t.Views().Main().Content(Contains("/John Doe <john@doe.com>/"))
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,53 @@
|
||||
package commit
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var CreateFixupCommitInBranchStack = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Create a fixup commit in a stack of branches, verify that it is created at the end of the branch it belongs to",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
GitVersion: AtLeast("2.38.0"),
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.NewBranch("branch1")
|
||||
shell.EmptyCommit("branch1 commit 1")
|
||||
shell.EmptyCommit("branch1 commit 2")
|
||||
shell.EmptyCommit("branch1 commit 3")
|
||||
shell.NewBranch("branch2")
|
||||
shell.EmptyCommit("branch2 commit 1")
|
||||
shell.EmptyCommit("branch2 commit 2")
|
||||
shell.CreateFileAndAdd("fixup-file", "fixup content")
|
||||
|
||||
shell.SetConfig("rebase.updateRefs", "true")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("CI ◯ branch2 commit 2"),
|
||||
Contains("CI ◯ branch2 commit 1"),
|
||||
Contains("CI ◯ * branch1 commit 3"),
|
||||
Contains("CI ◯ branch1 commit 2"),
|
||||
Contains("CI ◯ branch1 commit 1"),
|
||||
).
|
||||
NavigateToLine(Contains("branch1 commit 2")).
|
||||
Press(keys.Commits.CreateFixupCommit).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Create fixup commit")).
|
||||
Select(Contains("fixup! commit")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("CI ◯ branch2 commit 2"),
|
||||
Contains("CI ◯ branch2 commit 1"),
|
||||
Contains("CI ◯ * fixup! branch1 commit 2"),
|
||||
Contains("CI ◯ branch1 commit 3"),
|
||||
Contains("CI ◯ branch1 commit 2"),
|
||||
Contains("CI ◯ branch1 commit 1"),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,57 @@
|
||||
package conflicts
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var ResolveWithoutTrailingLf = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Regression test for resolving a merge conflict when the file doesn't have a trailing newline",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
NewBranch("branch1").
|
||||
CreateFileAndAdd("file", "a\n\nno eol").
|
||||
Commit("initial commit").
|
||||
UpdateFileAndAdd("file", "a1\n\nno eol").
|
||||
Commit("commit on branch1").
|
||||
NewBranchFrom("branch2", "HEAD^").
|
||||
UpdateFileAndAdd("file", "a2\n\nno eol").
|
||||
Commit("commit on branch2").
|
||||
Checkout("branch1").
|
||||
RunCommandExpectError([]string{"git", "merge", "--no-edit", "branch2"})
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Contains("UU file").IsSelected(),
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
t.Views().MergeConflicts().
|
||||
IsFocused().
|
||||
SelectedLines(
|
||||
Contains("<<<<<<< HEAD"),
|
||||
Contains("a1"),
|
||||
Contains("======="),
|
||||
).
|
||||
SelectNextItem().
|
||||
PressPrimaryAction()
|
||||
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Continue")).
|
||||
Content(Contains("All merge conflicts resolved. Continue?")).
|
||||
Cancel()
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("M file").IsSelected(),
|
||||
)
|
||||
|
||||
t.Views().Main().Content(Contains("-a1\n+a2\n").DoesNotContain("-no eol"))
|
||||
},
|
||||
})
|
||||
@@ -127,6 +127,26 @@ var DiffContextChange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains(`+3b`),
|
||||
Contains(` 4a`),
|
||||
).
|
||||
Press(keys.Universal.DecreaseContextInDiffView).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Changed diff context size to 0"))
|
||||
}).
|
||||
SelectedLines(
|
||||
Contains(`@@ -3,1 +3 @@`),
|
||||
Contains(`-3a`),
|
||||
Contains(`+3b`),
|
||||
).
|
||||
Press(keys.Universal.IncreaseContextInDiffView).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Changed diff context size to 1"))
|
||||
}).
|
||||
SelectedLines(
|
||||
Contains(`@@ -2,3 +2,3 @@`),
|
||||
Contains(` 2a`),
|
||||
Contains(`-3a`),
|
||||
Contains(`+3b`),
|
||||
Contains(` 4a`),
|
||||
).
|
||||
Press(keys.Universal.IncreaseContextInDiffView).
|
||||
Tap(func() {
|
||||
t.ExpectToast(Equals("Changed diff context size to 2"))
|
||||
|
||||
@@ -43,6 +43,7 @@ var tests = []*components.IntegrationTest{
|
||||
branch.CreateTag,
|
||||
branch.Delete,
|
||||
branch.DeleteRemoteBranchWithCredentialPrompt,
|
||||
branch.DeleteRemoteBranchWithDifferentName,
|
||||
branch.DetachedHead,
|
||||
branch.NewBranchAutostash,
|
||||
branch.NewBranchFromRemoteTrackingDifferentName,
|
||||
@@ -65,6 +66,7 @@ var tests = []*components.IntegrationTest{
|
||||
branch.SetUpstream,
|
||||
branch.ShowDivergenceFromBaseBranch,
|
||||
branch.ShowDivergenceFromUpstream,
|
||||
branch.ShowDivergenceFromUpstreamNoDivergence,
|
||||
branch.SortLocalBranches,
|
||||
branch.SortRemoteBranches,
|
||||
branch.SquashMerge,
|
||||
@@ -86,7 +88,9 @@ var tests = []*components.IntegrationTest{
|
||||
commit.CommitWithGlobalPrefix,
|
||||
commit.CommitWithNonMatchingBranchName,
|
||||
commit.CommitWithPrefix,
|
||||
commit.CopyAuthorToClipboard,
|
||||
commit.CreateAmendCommit,
|
||||
commit.CreateFixupCommitInBranchStack,
|
||||
commit.CreateTag,
|
||||
commit.DiscardOldFileChanges,
|
||||
commit.FindBaseCommitForFixup,
|
||||
@@ -119,6 +123,7 @@ var tests = []*components.IntegrationTest{
|
||||
conflicts.ResolveExternally,
|
||||
conflicts.ResolveMultipleFiles,
|
||||
conflicts.ResolveNoAutoStage,
|
||||
conflicts.ResolveWithoutTrailingLf,
|
||||
conflicts.UndoChooseHunk,
|
||||
custom_commands.AccessCommitProperties,
|
||||
custom_commands.BasicCommand,
|
||||
@@ -341,6 +346,7 @@ var tests = []*components.IntegrationTest{
|
||||
tag.ForceTagLightweight,
|
||||
tag.Reset,
|
||||
ui.Accordion,
|
||||
ui.DisableSwitchTabWithPanelJumpKeys,
|
||||
ui.DoublePopup,
|
||||
ui.EmptyMenu,
|
||||
ui.KeybindingSuggestionsWhenSwitchingRepos,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var DisableSwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Verify that the tab does not change by default when jumping to an already focused panel",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Status().Focus().
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
t.Views().Files().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
|
||||
// Despite jumping to an already focused panel,
|
||||
// the tab should not change from the base files view
|
||||
t.Views().Files().IsFocused()
|
||||
},
|
||||
})
|
||||
@@ -50,7 +50,7 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
shell.CreateFile("file1", fileContent)
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
assertRangeSelectBehaviour := func(v *ViewDriver) {
|
||||
assertRangeSelectBehaviour := func(v *ViewDriver, otherView *ViewDriver, lineIdxOfFirstItem int) {
|
||||
v.
|
||||
SelectedLines(
|
||||
Contains("line 1"),
|
||||
@@ -152,9 +152,21 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
SelectedLines(
|
||||
Contains("line 10"),
|
||||
)
|
||||
|
||||
// Click in view, press shift+arrow -> nonsticky range
|
||||
otherView.Focus()
|
||||
v.Click(1, lineIdxOfFirstItem).
|
||||
SelectedLines(
|
||||
Contains("line 1"),
|
||||
).
|
||||
Press(keys.Universal.RangeSelectDown).
|
||||
SelectedLines(
|
||||
Contains("line 1"),
|
||||
Contains("line 2"),
|
||||
)
|
||||
}
|
||||
|
||||
assertRangeSelectBehaviour(t.Views().Commits().Focus())
|
||||
assertRangeSelectBehaviour(t.Views().Commits().Focus(), t.Views().Branches(), 0)
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
@@ -163,6 +175,6 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
).
|
||||
PressEnter()
|
||||
|
||||
assertRangeSelectBehaviour(t.Views().Staging().IsFocused())
|
||||
assertRangeSelectBehaviour(t.Views().Staging().IsFocused(), t.Views().Files(), 6)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -6,10 +6,12 @@ import (
|
||||
)
|
||||
|
||||
var SwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Switch tab with the panel jump keys",
|
||||
Description: "Switch tab with the panel jump keys after enabling the feature",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().Gui.SwitchTabsWithPanelJumpKeys = true
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
|
||||
+10
-5
@@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
@@ -12,14 +13,18 @@ func ForEachLineInFile(path string, f func(string, int)) error {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := bufio.NewReader(file)
|
||||
forEachLineInStream(file, f)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func forEachLineInStream(reader io.Reader, f func(string, int)) {
|
||||
bufferedReader := bufio.NewReader(reader)
|
||||
for i := 0; true; i++ {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
line, _ := bufferedReader.ReadString('\n')
|
||||
if len(line) == 0 {
|
||||
break
|
||||
}
|
||||
f(line, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_forEachLineInStream(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
input string
|
||||
expectedLines []string
|
||||
}{
|
||||
{
|
||||
name: "empty input",
|
||||
input: "",
|
||||
expectedLines: []string{},
|
||||
},
|
||||
{
|
||||
name: "single line",
|
||||
input: "abc\n",
|
||||
expectedLines: []string{"abc\n"},
|
||||
},
|
||||
{
|
||||
name: "single line without line feed",
|
||||
input: "abc",
|
||||
expectedLines: []string{"abc"},
|
||||
},
|
||||
{
|
||||
name: "multiple lines",
|
||||
input: "abc\ndef\n",
|
||||
expectedLines: []string{"abc\n", "def\n"},
|
||||
},
|
||||
{
|
||||
name: "multiple lines including empty lines",
|
||||
input: "abc\n\ndef\n",
|
||||
expectedLines: []string{"abc\n", "\n", "def\n"},
|
||||
},
|
||||
{
|
||||
name: "multiple lines without linefeed at end of file",
|
||||
input: "abc\ndef\nghi",
|
||||
expectedLines: []string{"abc\n", "def\n", "ghi"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
lines := []string{}
|
||||
forEachLineInStream(strings.NewReader(s.input), func(line string, i int) {
|
||||
lines = append(lines, line)
|
||||
})
|
||||
assert.EqualValues(t, s.expectedLines, lines)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -221,13 +221,13 @@ func moveTodosUp(todos []todo.Todo, todosToMove []Todo) ([]todo.Todo, error) {
|
||||
return todos, nil
|
||||
}
|
||||
|
||||
func MoveFixupCommitDown(fileName string, originalHash string, fixupHash string, commentChar byte) error {
|
||||
func MoveFixupCommitDown(fileName string, originalHash string, fixupHash string, changeToFixup bool, commentChar byte) error {
|
||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newTodos, err := moveFixupCommitDown(todos, originalHash, fixupHash)
|
||||
newTodos, err := moveFixupCommitDown(todos, originalHash, fixupHash, changeToFixup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -235,7 +235,7 @@ func MoveFixupCommitDown(fileName string, originalHash string, fixupHash string,
|
||||
return WriteRebaseTodoFile(fileName, newTodos, commentChar)
|
||||
}
|
||||
|
||||
func moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash string) ([]todo.Todo, error) {
|
||||
func moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash string, changeToFixup bool) ([]todo.Todo, error) {
|
||||
isOriginal := func(t todo.Todo) bool {
|
||||
return (t.Command == todo.Pick || t.Command == todo.Merge) && equalHash(t.Commit, originalHash)
|
||||
}
|
||||
@@ -259,7 +259,9 @@ func moveFixupCommitDown(todos []todo.Todo, originalHash string, fixupHash strin
|
||||
|
||||
newTodos := MoveElement(todos, fixupIndex, originalIndex+1)
|
||||
|
||||
newTodos[originalIndex+1].Command = todo.Fixup
|
||||
if changeToFixup {
|
||||
newTodos[originalIndex+1].Command = todo.Fixup
|
||||
}
|
||||
|
||||
return newTodos, nil
|
||||
}
|
||||
|
||||
@@ -266,23 +266,40 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
todos []todo.Todo
|
||||
originalHash string
|
||||
fixupHash string
|
||||
changeToFixup bool
|
||||
expectedTodos []todo.Todo
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "fixup commit is the last commit",
|
||||
name: "fixup commit is the last commit (change to fixup)",
|
||||
todos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "original"},
|
||||
{Command: todo.Pick, Commit: "fixup"},
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "original"},
|
||||
{Command: todo.Fixup, Commit: "fixup"},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "fixup commit is the last commit (don't change to fixup)",
|
||||
todos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "original"},
|
||||
{Command: todo.Pick, Commit: "fixup"},
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: false,
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "original"},
|
||||
{Command: todo.Pick, Commit: "fixup"},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "fixup commit is separated from original commit",
|
||||
todos: []todo.Todo{
|
||||
@@ -290,8 +307,9 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
{Command: todo.Pick, Commit: "other"},
|
||||
{Command: todo.Pick, Commit: "fixup"},
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "original"},
|
||||
{Command: todo.Fixup, Commit: "fixup"},
|
||||
@@ -306,8 +324,9 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
{Command: todo.Pick, Commit: "other"},
|
||||
{Command: todo.Pick, Commit: "fixup"},
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Merge, Commit: "original"},
|
||||
{Command: todo.Fixup, Commit: "fixup"},
|
||||
@@ -324,6 +343,7 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: nil,
|
||||
expectedErr: errors.New("Expected exactly one original hash, found 2"),
|
||||
},
|
||||
@@ -336,6 +356,7 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: nil,
|
||||
expectedErr: errors.New("Expected exactly one fixup hash, found 2"),
|
||||
},
|
||||
@@ -346,6 +367,7 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: nil,
|
||||
expectedErr: errors.New("Expected exactly one fixup hash, found 0"),
|
||||
},
|
||||
@@ -356,6 +378,7 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
},
|
||||
originalHash: "original",
|
||||
fixupHash: "fixup",
|
||||
changeToFixup: true,
|
||||
expectedTodos: nil,
|
||||
expectedErr: errors.New("Expected exactly one original hash, found 0"),
|
||||
},
|
||||
@@ -363,7 +386,7 @@ func TestRebaseCommands_moveFixupCommitDown(t *testing.T) {
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(scenario.name, func(t *testing.T) {
|
||||
actualTodos, actualErr := moveFixupCommitDown(scenario.todos, scenario.originalHash, scenario.fixupHash)
|
||||
actualTodos, actualErr := moveFixupCommitDown(scenario.todos, scenario.originalHash, scenario.fixupHash, scenario.changeToFixup)
|
||||
|
||||
if scenario.expectedErr == nil {
|
||||
assert.NoError(t, actualErr)
|
||||
|
||||
@@ -452,6 +452,21 @@
|
||||
],
|
||||
"description": "Status panel view.\nOne of 'dashboard' (default) | 'allBranchesLog'",
|
||||
"default": "dashboard"
|
||||
},
|
||||
"switchToFilesAfterStashPop": {
|
||||
"type": "boolean",
|
||||
"description": "If true, jump to the Files panel after popping a stash",
|
||||
"default": true
|
||||
},
|
||||
"switchToFilesAfterStashApply": {
|
||||
"type": "boolean",
|
||||
"description": "If true, jump to the Files panel after applying a stash",
|
||||
"default": true
|
||||
},
|
||||
"switchTabsWithPanelJumpKeys": {
|
||||
"type": "boolean",
|
||||
"description": "If true, when using the panel jump keys (default 1 through 5) and target panel is already active, go to next tab instead",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
|
||||
+61
@@ -183,6 +183,10 @@ type View struct {
|
||||
// if true, the user can scroll all the way past the last item until it appears at the top of the view
|
||||
CanScrollPastBottom bool
|
||||
|
||||
// if true, the view will automatically recognize https: URLs in the content written to it and render
|
||||
// them as hyperlinks
|
||||
AutoRenderHyperLinks bool
|
||||
|
||||
// if true, the view will underline hyperlinks only when the cursor is on
|
||||
// them; otherwise, they will always be underlined
|
||||
UnderlineHyperLinksOnlyOnHover bool
|
||||
@@ -780,6 +784,7 @@ func (v *View) writeRunes(p []rune) {
|
||||
for _, r := range p {
|
||||
switch r {
|
||||
case '\n':
|
||||
v.autoRenderHyperlinksInCurrentLine()
|
||||
if c, ok := v.readCell(v.wx+1, v.wy); !ok || c.chr == 0 {
|
||||
v.writeCells(v.wx, v.wy, []cell{{
|
||||
chr: 0,
|
||||
@@ -793,6 +798,7 @@ func (v *View) writeRunes(p []rune) {
|
||||
v.lines = append(v.lines, nil)
|
||||
}
|
||||
case '\r':
|
||||
v.autoRenderHyperlinksInCurrentLine()
|
||||
if c, ok := v.readCell(v.wx, v.wy); !ok || c.chr == 0 {
|
||||
v.writeCells(v.wx, v.wy, []cell{{
|
||||
chr: 0,
|
||||
@@ -829,6 +835,61 @@ func (v *View) writeString(s string) {
|
||||
v.writeRunes([]rune(s))
|
||||
}
|
||||
|
||||
func findSubstring(line []cell, substringToFind []rune) int {
|
||||
for i := 0; i < len(line)-len(substringToFind); i++ {
|
||||
for j := 0; j < len(substringToFind); j++ {
|
||||
if line[i+j].chr != substringToFind[j] {
|
||||
break
|
||||
}
|
||||
if j == len(substringToFind)-1 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (v *View) autoRenderHyperlinksInCurrentLine() {
|
||||
if !v.AutoRenderHyperLinks {
|
||||
return
|
||||
}
|
||||
|
||||
// We need a heuristic to find the end of a hyperlink. Searching for the
|
||||
// first character that is not a valid URI character is not quite good
|
||||
// enough, because in markdown it's common to have a hyperlink followed by a
|
||||
// ')', so we want to stop there. Hopefully URLs containing ')' are uncommon
|
||||
// enough that this is not a problem.
|
||||
lineEndCharacters := map[rune]bool{
|
||||
'\000': true,
|
||||
' ': true,
|
||||
'\n': true,
|
||||
'>': true,
|
||||
'"': true,
|
||||
')': true,
|
||||
}
|
||||
line := v.lines[v.wy]
|
||||
start := 0
|
||||
for {
|
||||
linkStart := findSubstring(line[start:], []rune("https://"))
|
||||
if linkStart == -1 {
|
||||
break
|
||||
}
|
||||
linkStart += start
|
||||
link := ""
|
||||
linkEnd := linkStart
|
||||
for ; linkEnd < len(line); linkEnd++ {
|
||||
if _, ok := lineEndCharacters[line[linkEnd].chr]; ok {
|
||||
break
|
||||
}
|
||||
link += string(line[linkEnd].chr)
|
||||
}
|
||||
for i := linkStart; i < linkEnd; i++ {
|
||||
v.lines[v.wy][i].hyperlink = link
|
||||
}
|
||||
start = linkEnd
|
||||
}
|
||||
}
|
||||
|
||||
// parseInput parses char by char the input written to the View. It returns nil
|
||||
// while processing ESC sequences. Otherwise, it returns a cell slice that
|
||||
// contains the processed data.
|
||||
|
||||
Vendored
+1
-1
@@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
|
||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
|
||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
|
||||
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20240906064314-bfab49c720d7
|
||||
# github.com/jesseduffield/gocui v0.3.1-0.20240928100326-393cf89a5d3f
|
||||
## explicit; go 1.12
|
||||
github.com/jesseduffield/gocui
|
||||
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||
|
||||
Reference in New Issue
Block a user