Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ contents with the local ~HEAD~ snapshot. Existing remote text documents
are still updated through text OT when supported; other entries use
Overleaf upload and delete APIs. Use this command only when the local
state is intended to replace the remote state. The interactive command
always asks for confirmation.
always asks for confirmation. This is git-overleaf's semantic equivalent
of ~git push --force~.

A successful overwrite also abandons and clears a pending Overleaf pull,
so this command is the recovery path after a pull was manually aborted or
Expand Down Expand Up @@ -546,11 +547,15 @@ then fetch, pull, or push. Selecting it asks for confirmation, registers
the default name (or prompts for another name after a collision), and
continues the requested operation. These actions are branchless: fetch
updates only ~refs/git-overleaf/remote~, pull runs ~git-overleaf-pull~, and
push runs ~git-overleaf-push~. Active Git-only transient arguments are
rejected. Selecting the logical remote from Magit's ordinary "fetch
push normally runs ~git-overleaf-push~. The push action honors Magit's
force arguments: =-f= (force with lease) uses the same guarded push because
git-overleaf already rejects a remote snapshot that differs from its
recorded base, while =-F= (force) asks for confirmation and runs
~git-overleaf-overwrite-remote~. Other active Git-only transient arguments
are rejected. Selecting the logical remote from Magit's ordinary "fetch
elsewhere" action also routes a no-argument fetch through git-overleaf;
branches and refspecs are unsupported. All other Git remotes retain
Magit's normal behavior. Explicit =O= fetch bypasses the automatic
Magit's normal behavior. Explicit =O= fetch bypasses the automatic remote
refresh throttle.

On the Overleaf section, =G= refreshes the remote and =RET= opens the
Expand All @@ -563,7 +568,7 @@ project in a browser. =C-c C-c= is a command prefix with these keys:
| =l= | Pull from Overleaf. |
| =p= | Push to Overleaf. |
| =r= | Register the logical Overleaf remote. |
| =O= | Overwrite the remote after confirmation. |
| =O= | Force-push to the remote after confirmation. |
| =L= | Show the git-overleaf log. |
| =k= | Stop background Overleaf operations. |

Expand Down
16 changes: 10 additions & 6 deletions README.zh.org
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ M-x git-overleaf-overwrite-remote
这是一个恢复命令。它使用与 ~git-overleaf-push~ 相同的本地准备流程,但
总是用本地 ~HEAD~ 快照替换远端 Overleaf 项目内容。已有远端文本文档在支持
时仍会通过文本 OT 更新;其他条目使用 Overleaf 上传和删除 API。只有在确实
希望本地状态替换远端状态时才应使用该命令。交互式运行时总会要求确认。
希望本地状态替换远端状态时才应使用该命令。交互式运行时总会要求确认。它在
语义上等价于 ~git push --force~。

成功覆盖还会放弃并清除 pending Overleaf pull,因此手动中止 pull 的 merge
或 pending 元数据过期时,可以用该命令恢复。命令不会自动中止 Git merge,
Expand Down Expand Up @@ -481,10 +482,13 @@ Magit 的 fetch、pull 和 push transient 都会增加一个大写 =O= 动作,
fetch/pull/push”;选择后先请求确认,使用默认名字注册(若同名 remote 已存在,
则提示输入另一个名字),再继续原操作。它们不接受分支:fetch 只更新
~refs/git-overleaf/remote~,pull 调用 ~git-overleaf-pull~,push 调用
~git-overleaf-push~。已启用的 Git 专用 transient 参数会被拒绝。从 Magit
普通的 “fetch elsewhere” 选择该逻辑 remote 且不提供参数时,也会转交给
git-overleaf;分支和 refspec 不受支持。其他 Git remote 仍保持 Magit 原始
行为。显式 =O= fetch 不受自动刷新节流限制。
~git-overleaf-push~。push 动作支持 Magit 的 force 参数:=-f=(force with
lease)仍走安全 push,因为 git-overleaf 已经会拒绝与已记录 base 不同的远端
快照;=-F=(force)则先请求确认,再调用
~git-overleaf-overwrite-remote~。其他已启用的 Git 专用 transient 参数会被
拒绝。从 Magit 普通的 “fetch elsewhere” 选择该逻辑 remote 且不提供参数时,
也会转交给 git-overleaf;分支和 refspec 不受支持。其他 Git remote 仍保持
Magit 原始行为。显式 =O= fetch 不受自动刷新节流限制。

在 Overleaf section 上,=G= 刷新远端,=RET= 在浏览器中打开项目。
=C-c C-c= 是命令前缀,包含:
Expand All @@ -496,7 +500,7 @@ git-overleaf;分支和 refspec 不受支持。其他 Git remote 仍保持 Magi
| =l= | 从 Overleaf 拉取。 |
| =p= | 推送到 Overleaf。 |
| =r= | 注册逻辑 Overleaf remote。 |
| =O= | 确认后覆盖远端。 |
| =O= | 确认后 force-push 到远端。 |
| =L= | 显示 git-overleaf 日志。 |
| =k= | 停止后台 Overleaf 操作。 |

Expand Down
31 changes: 26 additions & 5 deletions git-overleaf-magit.el
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,24 @@ runs from status insertion or automatic refresh paths."
"Git arguments do not apply to Overleaf: %s"
(mapconcat #'identity args " ")))))

(defun git-overleaf-magit--push-mode (args)
"Return the Overleaf push mode selected by Magit ARGS.
No arguments and `--force-with-lease' select the normal guarded push.
The Git `-f' and `--force' arguments select a remote overwrite. Signal
when ARGS contains any other argument or combines the two force modes."
(cond
((null args) 'normal)
((equal args '("--force-with-lease")) 'normal)
((and (null (cdr args))
(member (car args) '("-f" "--force")))
'force)
(t
(user-error
(concat
"Only --force-with-lease and --force apply to Overleaf pushes; "
"got: %s")
(mapconcat #'identity args " ")))))

(transient-define-suffix git-overleaf-magit-fetch ()
"Fetch the branchless logical Overleaf remote."
:description #'git-overleaf-magit--fetch-description
Expand All @@ -524,17 +542,20 @@ runs from status insertion or automatic refresh paths."
(git-overleaf--async-supported-p)))
(call-interactively #'git-overleaf-pull))))

(transient-define-suffix git-overleaf-magit-push ()
(transient-define-suffix git-overleaf-magit-push (args)
"Push the branchless logical Overleaf remote."
:description #'git-overleaf-magit--push-description
(interactive)
(git-overleaf-magit--reject-arguments 'magit-push)
(let ((repo (git-overleaf-magit--require-managed-repo)))
(interactive (list (magit-push-arguments)))
(let ((mode (git-overleaf-magit--push-mode args))
(repo (git-overleaf-magit--require-managed-repo)))
(git-overleaf-magit--ensure-registered-remote repo "push")
(let ((default-directory repo)
(git-overleaf-enable-async
(git-overleaf--async-supported-p)))
(call-interactively #'git-overleaf-push))))
(call-interactively
(if (eq mode 'force)
#'git-overleaf-overwrite-remote
#'git-overleaf-push)))))

(defun git-overleaf-magit--around-git-fetch (function remote args)
"Route a branchless fetch of logical REMOTE through git-overleaf.
Expand Down
38 changes: 38 additions & 0 deletions test/git-overleaf-magit-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@
(equal (git-overleaf-magit--operation-description "fetch")
"Overleaf"))))

(ert-deftest git-overleaf-magit-test-push-mode ()
(should (eq (git-overleaf-magit--push-mode nil) 'normal))
(should
(eq (git-overleaf-magit--push-mode '("--force-with-lease"))
'normal))
(should (eq (git-overleaf-magit--push-mode '("-f")) 'force))
(should (eq (git-overleaf-magit--push-mode '("--force")) 'force))
(should-error
(git-overleaf-magit--push-mode '("--dry-run"))
:type 'user-error)
(should-error
(git-overleaf-magit--push-mode '("--force-with-lease" "--force"))
:type 'user-error))

(ert-deftest git-overleaf-magit-test-push-dispatches-force-modes ()
(let (commands)
(cl-letf (((symbol-function 'git-overleaf-magit--require-managed-repo)
(lambda () "/repo"))
((symbol-function
'git-overleaf-magit--ensure-registered-remote)
(lambda (_repo _operation) "overleaf"))
((symbol-function 'git-overleaf--async-supported-p)
(lambda () t))
((symbol-function 'call-interactively)
(lambda (command &rest _args)
(push command commands))))
(git-overleaf-magit-push nil)
(git-overleaf-magit-push '("--force-with-lease"))
(git-overleaf-magit-push '("-f"))
(git-overleaf-magit-push '("--force"))
(should
(equal
(nreverse commands)
'(git-overleaf-push
git-overleaf-push
git-overleaf-overwrite-remote
git-overleaf-overwrite-remote))))))

(ert-deftest git-overleaf-magit-test-ensure-remote-reuses-existing ()
(cl-letf (((symbol-function 'git-overleaf--remote-name)
(lambda (_repo) "paper"))
Expand Down
Loading