2

前言:

提交时,我倾向于将消息格式化如下:

[<task number>] <task title>

应该通过 pre-push 挂钩将其转换为有效的 GitHub 语法,如下所示:

Work item [[<git_branch>](http://tracker/_workitems/<git_branch>)]:

- [x] [[<task_number>](http://tracker/_workitems/<task_number>)] <task title>

然后将其cat转换为控制台输出,因此我可以将其复制粘贴到 github 上的 PR 描述中。

任务

更进一步,将该消息放入剪贴板,这样我就不必手动选择它并从控制台复制。因为我在 Linux 机器上,所以我决定使用xclip这个任务。

我当前的 git hook 脚本如下所示:

#!/bin/sh

PBI=\`git symbolic-ref --short HEAD\`

echo "**Backlog Item [$PBI]:**\n" > pr_messages/$PBI.md

git log develop..HEAD --format=" - [x] %B" >> pr_messages/$PBI.md

sed -r -i 's|\[([0-9]{4,})\]|[[\1](http://tracker/_workitems/\1)]|g' pr_messages/$PBI.md

cat pr_messages/$PBI.md

问题

当我将以下行添加到此脚本的末尾时

cat pr_messages/$PBI.md | xclip -selection clipboard

我在 Ctrl+C/V 剪贴板中收到消息,但 git 挂起,我必须中止它。鉴于它应该是一个 pre-push 钩子,它有效地阻止了我实际推送我的代码。

UPD:正如@wumpus-q-wumbley 所建议的,这是 strace 输出:

$> ps aux | grep git

kraplax  29796  0.0  0.0  25696  5660 pts/1    S+   12:55   0:00 git push
kraplax  29797  0.0  0.0  48276  3040 pts/1    S+   12:55   0:00 ssh git@github.com git-receive-pack 'eduard-sukharev/ProFIT.git'

$> sudo strace -p 29796
Process 29796 attached
wait4(29797, 
^CProcess 29796 detached
 <detached ...>
$> sudo strace -p 29797
Process 29797 attached
select(7, [3 4], [], NULL, NULL
^CProcess 29797 detached
 <detached ...>

这基本上表明 git-push 正在等待ssh git@github.com git-receive-pack 'eduard-sukharev/ProFIT.git'挂起的 ssh 进程。这一切都稍微转移了问题的焦点。

UPD2:设置GIT_TRACE=~/git_trace.log提供此信息:

$ cat ../git_trace.log 
trace: built-in: git 'rev-parse' '--abbrev-ref' 'HEAD'
trace: built-in: git 'rev-parse' '--abbrev-ref' 'HEAD'
trace: built-in: git 'status' '--porcelain'
trace: built-in: git 'push'
trace: run_command: 'ssh' 'git@github.com' 'git-receive-pack '\''eduard-sukharev/ProFIT.git'\'''
trace: run_command: '.git/hooks/pre-push' 'origin' 'git@github.com:eduard-sukharev/ProFIT.git'
trace: built-in: git 'symbolic-ref' '--short' 'HEAD'
trace: built-in: git 'log' 'develop..HEAD' '--format= - [x] %B'
trace: built-in: git 'rev-parse' '--abbrev-ref' 'HEAD'
trace: built-in: git 'status' '--porcelain'

问题

如果没有,为什么这个过程会挂起?

我应该如何重写那行来完成预期的任务?

我应该使用其他工具来管理剪贴板xclip吗?

4

2 回答 2

2

xsel,以及xclip,等到另一个程序显式获取所选数据。

这种行为是 X11 的设计条件,因为“没有 X 选择缓冲区。X11 中的选择机制是每次任何程序希望知道选择内容时由 X 服务器调解的客户端间通信 [...]。在为了实现对选择的修改(在输入、保持和交换模式下)[这些程序分离]从终端,产生一个子进程来按需提供新的选择。当任何其他的时候,这个子进程立即退出程序接管选择” ——来自 xsel 手册页

换句话说,您的 Gitspre-push提交会一直执行,直到您开始向剪贴板提供文本选择。然后停止该过程,直到您通过调用任何命令或执行任何“获取”剪贴板文本的程序来使用此文本片段。

分叉xclip- 命令不起作用

我的第一个想法是分离这个提供选择的过程,让它与(当时)正在进行的钩子脚本的执行并行。不幸的是,这不起作用,要么主进程停止,直到子进程返回,要么当前 X11 服务器无法使用分叉命令的文本选择。

可能的解决方案

由于 X11 中“剪贴板”的行为,您必须避免在 git-hooks 的时间相关处理中提供文本选择。

  1. 使用剪贴板管理器- 大多数剪贴板管理器(如Klipper [for KDE] 或Glipper [for Gnome])提供了将数据供应与其使用分离的机制——它模拟了 Windows 和 Mac OS 的剪贴板行为。

  2. 别名git-push-command - 如果您主要在 shell 中操作 git-repository,则可以将git-push-command 包装在别名或小型 shell 脚本中,该脚本首先调用推送,然后将文本片段提供给剪贴板。这种方法的缺点是(除了 cli 依赖项之外)命令将在最后“挂起”,直到您获取剪贴板内容。

除非您无法在系统中安装其他软件,否则我建议您使用剪贴板管理器。

使用 Klipper 将 CLI 中的文本放入 X11 剪贴板

您可以使用qdbus(Qt 应用程序的命令行界面)通过 shell 访问 Klipper 。取自Milian Wolff 的博客文章的示例,根据您的脚本改编,可能如下所示:

#!/bin/sh

PBI=\`git symbolic-ref --short HEAD\`
echo "**Backlog Item [$PBI]:**\n" > pr_messages/$PBI.md
git log develop..HEAD --format=" - [x] %B" >> pr_messages/$PBI.md

sed -r -i 's|\[([0-9]{4,})\]|[[\1](http://tracker/_workitems/\1)]|g' pr_messages/$PBI.md

PR_MESSAGE=$(cat pr_messages/$PBI.md)
qdbus org.kde.klipper /klipper setClipboardContents "$PR_MESSAGE"

另一篇关于 qdbus 和 Klipper 交互的有趣文章:https ://askubuntu.com/questions/393601/a-command-for-pasting-the-same-as-ctrl-v

于 2015-09-15T11:05:36.623 回答
0

我怀疑 xclip 后台进程在脚本的原始标准输出上仍然有一个打开的文件描述符,从而阻止 git 在它读取钩子输出的管道上接收 EOF。尝试添加> /dev/null到 xclip 命令。

于 2015-08-06T12:49:14.270 回答