序言:
提交时我倾向于将消息格式化如下:
[<task number>] <task title>
应通过预推送 Hook 将其转换为有效的 GitHub 语法,如下所示:
Work item [[<git_branch>](http://tracker/_workitems/<git_branch>)]:
- [x] [[<task_number>](http://tracker/_workitems/<task_number>)] <task title>
然后是cat
ted 到控制台输出,以便我可以将其复制粘贴到 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 挂起,我必须中止它。鉴于它应该是一个预推送钩子(Hook),它有效地阻止了我实际推送我的代码。
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 <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="44232d3004232d302c31266a272b29" rel="noreferrer noopener nofollow">[email protected]</a> 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 进程 ssh <a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0e69677a4e69677a667b6c206d6163" rel="noreferrer noopener nofollow">[email protected]</a> git-receive-pack 'eduard-sukharev/ProFIT.git'
哪个挂起。这一切都稍微转移了问题的焦点。
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' '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="83e4eaf7c3e4eaf7ebf6e1ade0ecee" rel="noreferrer noopener nofollow">[email protected]</a>' 'git-receive-pack '\''eduard-sukharev/ProFIT.git'\'''
trace: run_command: '.git/hooks/pre-push' 'origin' '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="65020c1125020c110d10074b060a08" rel="noreferrer noopener nofollow">[email protected]</a>: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
之外,我是否应该使用其他工具来管理剪贴板?
最佳答案
xsel
,以及xclip
,等待另一个程序显式获取所选数据。
This behavior is a design-conditional of X11, since there "is no X selection buffer. The selection mechanism in X11 is an interclient communication mediated by the X server each time any program wishes to know the selection contents [...]. In order to implement modification of the selection(s) (in input, keep and exchange modes) [these programs detach] from the terminal, spawning a child process to supply the new selection(s) on demand. This child exits immediately when any other program takes over the selection(s)" -- from the xsel man-page
换句话说,您的 Gits pre-push
提交将一直执行,直到您开始向剪贴板提供文本选择。然后,该过程将停止,直到您通过调用任何命令或执行任何“获取”剪贴板文本的程序来使用此文本片段。
fork xclip
- 命令不起作用
我的第一个想法是分离这个提供选择的过程,让它与(当时)正在进行的钩子(Hook)脚本执行并行。不幸的是,这不起作用,要么主进程无论如何都会停止,直到子进程返回,要么当前的 X11 服务器无法使用 fork 命令的文本选择。
可能的解决方案
由于 X11 中“剪贴板”的行为,您必须避免在 git-hooks 的时间相关处理中提供文本选择。
使用剪贴板管理器 - 大多数剪贴板管理器(如 Klipper [对于 KDE] 或 Glipper [对于 Gnome])提供了解耦数据供应的机制从它的用法来看 - 它模拟 Windows 和 Mac OS 的剪贴板行为。
别名
git-push
-command - 如果您主要在 shell 中操作 git-repository,则可以将git- 包装起来Push
- 别名或小型 shell 脚本中的命令,首先调用推送,然后将文本片段提供到剪贴板。这种方法的缺点是(除了 cli 依赖性之外)该命令将在最后“挂起”,直到您获取剪贴板内容。
除非您无法在系统中安装其他软件,否则我建议使用剪贴板管理器。
使用 Klipper 将 CLI 中的文本放入 X11 剪贴板
您可以使用 qdbus 通过 shell 访问 Klipper - Qt 应用程序的命令行界面。一个例子来自 Milian Wolff's Blog Post ,根据您的脚本进行调整,可能如下所示:
#!/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
关于Git 预推送 Hook 在管道传输到 xclip 后挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31855090/