When committing I tend to format message as following:
[<task number>] <task title>
which should be converted by pre-push hook to a valid GitHub syntax as following:
Work item [[<git_branch>](http://tracker/_workitems/<git_branch>)]:
- [x] [[<task_number>](http://tracker/_workitems/<task_number>)] <task title>
and then it's cat
ted to console output so i can copy-paste it to PR description on github.
Go one step further and put that message into clipboard so that I don't have to manually select it and copy from console.
Since I'm on Linux machine I decided that I'll use xclip
for the task.
My current git hook script looks as following:
#!/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
When I add following line to the end of this script
cat pr_messages/$PBI.md | xclip -selection clipboard
I get the message in my Ctrl+C/V clipboard, but git hangs and I have to abort it. Given that it's supposed to be a pre-push hook, it effectively prevents me from actually pushing my code.
UPD: As proposed by @wumpus-q-wumbley here's the strace output:
$> 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 [email protected] 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 ...>
Which essentially shows that git-push is waiting for the ssh process ssh [email protected] git-receive-pack 'eduard-sukharev/ProFIT.git'
which hangs. This all shifts the focus of the problem a bit.
UPD2: Setting GIT_TRACE=~/git_trace.log
gives this info:
$ 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' '[email protected]' 'git-receive-pack '\''eduard-sukharev/ProFIT.git'\'''
trace: run_command: '.git/hooks/pre-push' 'origin' '[email protected]: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'
Why does this process hang if otherwise it doesn't?
How should I rewrite that line to complete intended task?
Should I probably use other tool for managing clipboard, other than xclip
?
xsel
, as well as xclip
, waits until another program explicitly fetches the selected data.
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
With other words your Gits pre-push
commit is executed until you start providing your text-selection to the clipboard. The process is then halted until you are making use of this text-snippet by invoking any command or executing any program which "fetches" the clipboard text.
xclip
-command does not workMy first idea was to detach this selection-providing process to let it live parallel to the (then) ongoing execution of your hook-script. Unfortunately this does not work, either the main-process ist halting anyways, until the subprocess returns, or the text-selection of the forked command is not available to the current X11-server.
Due to the behavior of the "clipboard" in X11 you must evade providing text-selections in the time-relevant processing of git-hooks.
Use a clipboard-manager - The most clipboard-managers (like Klipper [for KDE] or Glipper [for Gnome]) provide mechanisms to decouple the supply of data from its usage - which emulates the clipboard behavior of Windows and Mac OS.
Alias the git-push
-command - if you're operating your git-repository mostly in the shell you might wrap the git-push
-command in an alias or small shell-script which first invokes the push and afterwards provides the text-snippet to the clipboard. The disadvantage of this approach is, (besides of the cli-dependency) that the command will "hang" at the end, until you fetched the clipboard-content.
Unless you're not able to install additional software to your system i'd recommend the use of a clipboard-manager.
You can access Klipper through the shell by using qdbus - a command-line-interface to Qt-applications. An example took from Milian Wolff's Blog Post, adapted to your script, may look like the following:
#!/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"
Another interesting article about the interaction of qdbus and Klipper: https://askubuntu.com/questions/393601/a-command-for-pasting-the-same-as-ctrl-v