每当我执行时git push
,我都必须在提示符下手动输入用户名和密码。
但是,我想自动执行此过程。
因此,我尝试使用管道将凭据传递给命令:
printf 'username\npassword' | git push
但输入用户名和密码的提示仍然没有消失!
为什么它不起作用?
笔记:
我知道这可以通过以下方式完成: 但我感兴趣的是知道管道方法有什么问题?
git push 'https://username:[email protected]/username/repo.git'
另外,为了确认此过程适用于其他情况,我做了一个实验。
我创建了一个脚本b.py
:
b.py
:
#!/usr/bin/env python3
username = input()
password = input()
log = open("log.txt", "w")
print(username + "\n" + password, file=log)
printf 'abcd\nefgh' | ./b.py
然后,我在终端中 执行,它确实按预期工作,并生成包含用户名和密码字符串的日志文件:
log.txt
:
abcd
efgh
答案1
按照您的示例,这仅适用于顺序提示是脚本的直接部分的情况。但是,如果git
您的值在任何用户名/密码提示之前被传递给进程 - 可能是在进程执行所有操作(网络等)之前GIT_ASKPASS
- 供参考:
https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables
答案2
先决条件
前段时间,GitHub 停止接受密码,而是要求用户创建令牌。当然,我记不住令牌,但我也不想将其作为纯文本存储在 中.git-credentials
。此外,我也不想将其作为参数传递(有人可以读取/proc
或.bash_history
找到它!)。我编写了一个简单的加密器来使用密码加密令牌,但就像你一样,无法将解密的令牌传输到管道,git
并在寻找解决方案时发现了这个问题。不幸的是,我没有在这里找到答案。然而,我很幸运地找到了一个不相关的问题,这让我找到了答案。答案是脚本。
解决方案
我们可以使用它script
创建一个自动会话并将凭据传递给它。这是我为其编写的脚本:
#!/bin/bash
read -p "Password: " -s password
echo
token=$(echo "$password" | decrypt_token) || exit $?
cmd="git push $@"
echo -e "username\n$token" | script -E never -c "$cmd" /dev/null
-E never
表示我不希望我的凭据被回显(打印在终端中)。我将其用作/dev/null
日志文件,因为我不关心日志记录。
重要的提示: echo
是我的 shell 中的一个内置命令,这意味着可以安全地将密码和令牌作为参数传递给它。如果它是外部程序,有人可能会从中读取参数/proc
。我建议您检查用于管道的命令是否内置在 shell 中。如果找不到合适的内置命令,请使用带有 heredoc 的 cat:
token=$(
(
cat <<EOF
$password
EOF
) | decrypt_token
)
第2部分
将我的设置复制到不同的机器后,我遇到了一个奇怪的错误:
fatal: could not read Password for 'https://[email protected]': Success
我检查了git
和screen
与原始机器上的版本是否相同,但未能找到根本原因。然而,此评论 可能提供提示:
getpass() tries too hard to find the real terminal
作为一种解决方法,我创建了一个单独的脚本GIT_ASKPASS
(我觉得这是一个更清晰的解决方案)。
这是更改后的主要脚本:
#!/bin/bash
if ! tty -s; then
echo "Can't operate without tty."
exit 1
fi
TTY=$(tty) GIT_USERNAME=username GIT_ASKPASS=~/git-creds git push $@
这是git-creds
:
#!/bin/bash
if echo "$1" | grep -q '^Password'; then
read -p "Password: " -s password < $TTY
echo "$password" | decrypt_token
# put a newline to separate prompt and output
echo > $TTY
else
echo "$GIT_USERNAME"
fi
它直接从您的 TTY 读取密码并将解密的令牌提供给 git。对于用户名,它只会回显 GIT_USERNAME 环境变量。
也可以添加这些行.bashrc
(或任何替代行):
export TTY=$(tty)
export GIT_USERNAME=username
export GIT_ASKPASS=~/git-creds
而且您不需要命令的包装器。