在终止 git 之前让 ctrl + c 要求确认

在终止 git 之前让 ctrl + c 要求确认

我有一个坏习惯,就是因为没有耐心而在程序运行时终止它们。对于我所做的 99% 的事情来说,这不会造成问题,因为我的程序通常不会编辑文件。

但是,这样做会导致 git 严重损坏。我花了几个小时才通过 ctrl + c 修复了几秒钟内出现的问题。

我希望终端问我“您确定要终止这个程序吗?如果在它完成之前终止它,您的生活将会很痛苦。”

是否可以?

答案1

机制

终端本身不能直接知道进程SIGINTCtrl+上接收了什么C它向前台进程组发送信号然后由内核向组中的每个成员传递信号。通常还有一个 shell,但 shell 不会中继信号;它只会通知终端哪个进程组在前台。

此机制允许Ctrl+C中断前台管道中的所有进程。终端所知道的只是当前前台进程组的 PGID(进程组 ID)。


修改终端

您可以修改终端,这样如果它要发送SIGINT,它将检查git前台进程组中是否存在并采取相应措施。(我认为您需要修改 tty/pts 驱动程序,而不是您最喜欢的终端仿真器;但这远远超出了我的专业知识,所以我可能是错的。)


修改 shell

如果 shell 中继,您可以修改其代码,在中继到(或包含 的进程组)SIGINT之前请求确认。但 shell 不会中继信号。要中继信号,修改后的 shell 应始终将自己单独置于前台(因此从终端只发送到 shell)并处理额外的前台-后台抽象级别,以便始终能够分辨出应该将信号中继到哪个进程组。这种天真的方法是不够的(调查和),shell 应该提供一个gitgitSIGINTSIGTTINSIGTTOU點數. 提供 pts 是终端多路复用器已经做的事情。


终端多路复用器

我不熟悉screen,我用的是tmux。该工具是有用 通过它自己,但现在最重要的是它能解决你的问题。

将此行添加到您的.tmux.conf

bind -T root 'C-c' if-shell 'tty="#{pane_tty}"; ps -eo tty,stat,comm | grep "^${tty#/dev/} .*+.* git$"' 'confirm-before -p "Git detected. Confirm SIGINT? (y/n)" "send-keys C-c"' 'send-keys C-c'

笔记:

  • 我用 测试了这个sleep,而不是git(因为我不使用git)。
  • ps -o stat不可移植。我在 Debian 10 上使用过psprocps-ng 3.3.15很有stat用,因为它可以打印+前台进程组中的进程。这个想法是git在后台忽略(如果有的话),因为Ctrl+无论如何C都不会发送SIGINT给它。

这个解决方案是我的个人选择(部分原因是我tmux每天都使用)。这是我的回答中唯一真正要求确认的解决方案。


修改git

您可以修改git以使其表现不同。我不一定是指 Git(即工具,尽管也可以修改它),而是指命令。您可以创建一个名为的包装器脚本或 shell 函数,git它将:

  • git以使其忽略的方式运行真实SIGINT
  • git或者在另一个从未在前台运行的进程组中运行实际进程,
  • 或者重新配置控制终端,运行真实的git,然后重新配置终端。

以下是在 Bash 中测试的示例函数。如果您决定创建名为 的包装器脚本(而不是函数)git并通过 提供PATH,则使用真实的完整路径git以避免脚本调用自身。


为了真正地git忽略它SIGINT,请将其包装在以下函数中:

git () ( trap '' INT; exec git "$@" )

注意函数体在子 shell 中运行,因此trap不会影响主 shell。但有缺点:

  • 真实git会忽略一切SIGINT(尽管它不会忽略SIGTERM)。
  • 如果git在管道中使用,则Ctrl+C仍会影响管道的其他部分。然后 realgit可能会因为 而退出SIGPIPE。我们trap '' PIPE也可以这样做,但我想您首先不想中断管道。

在另一个进程组中运行实际git(无论您如何操作)在我看来并不更好,有时甚至比上述“忽略SIGINT”解决方案更糟糕。


这是您来回重新配置终端的方法:

git () ( trap '' INT; stty -F /dev/tty intr '^G'; ( trap - INT; exec git "$@" ); stty -F /dev/tty intr '^C' )

现在只要git运行,Ctrl+C将不起作用;如果您确实想中断它,请改用Ctrl+ 。G

笔记:

  • 如果git在管道中使用,则Ctrl+C不会影响它的其他部分。Ctrl+G会影响整个管道。
  • 如果您在后台运行(包装器),那么由于尝试与控制终端交互,git它将立即暂停。为了避免这种情况,您可以在前台启动,并在第一次运行后,然后。在+时,shell 可能会恢复 tty 设置(Bash 会这样做),如果您打算这样做,这是幸运的;但是如果您这样做,您将能够再次使用+终止真实。sttygitCtrlZsttybgCtrlZbgfggitCtrlC
  • 如果前台管道中有两个或多个gits,那么第一个退出的 s 将恢复默认设置,而您肯定希望只有最后一个执行此操作。

相关内容