You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Git Bash中用户输入无法终止问题排查(Go语言Git钩子场景)

Git钩子Go语言输入在Git Bash中卡住的问题排查与解决

问题背景

在commit-msg钩子中用Go语言收集用户输入,Windows下打开CON设备,Mac/Linux下打开/dev/tty获取输入,该方案在PowerShell和CMD中运行正常,但在Git Bash环境下,输入内容并按回车后,程序始终处于等待输入的状态,无法继续执行。

附原代码(存在语法错误):

con, err := os.Open("CON")
if err == nil {
    os.Stdin = con
    reader := bufio.NewReader(os.Stdin)
    line, _ := reader.ReadString('\n' // 缺少闭合括号
}

原因分析

  1. Git Bash终端模拟特性:Git Bash基于MinGW/MSYS2模拟类Unix终端,Windows原生的CON设备在该环境下的输入流处理逻辑与CMD/PowerShell不同。直接将os.Stdin替换为CON的文件句柄后,bufio.ReadString('\n')无法正确识别Git Bash终端输入的换行信号,导致程序一直阻塞等待。
  2. 代码语法错误:原代码中ReadString('\n'缺少闭合括号,会引发编译异常,虽不直接导致Git Bash的阻塞问题,但属于必须修复的基础错误。
  3. 跨平台终端兼容性缺陷:直接操作系统原生设备文件(CON//dev/tty)缺乏统一的终端输入处理逻辑,不同终端环境下的换行符、输入缓冲机制差异会导致行为不一致。

解决方法

方法1:使用专业终端处理包(推荐)

借助golang.org/x/term包,它提供跨平台的终端输入处理能力,可自动适配Git Bash等不同终端环境,无需手动处理设备文件。

示例代码:

package main

import (
    "bufio"
    "fmt"
    "os"
    "golang.org/x/term"
)

func main() {
    // 保存原始终端状态,程序结束后恢复
    oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
    if err != nil {
        fmt.Printf("设置终端原始模式失败:%v\n", err)
        return
    }
    defer term.Restore(int(os.Stdin.Fd()), oldState)

    reader := bufio.NewReader(os.Stdin)
    fmt.Print("请输入内容:")
    line, err := reader.ReadString('\n')
    if err != nil {
        fmt.Printf("读取输入失败:%v\n", err)
        return
    }
    fmt.Printf("你输入的内容是:%s", line)
}

方法2:避免替换os.Stdin,直接使用打开的设备文件

不覆盖全局的os.Stdin,直接用打开的CON或/dev/tty文件作为输入源,同时处理不同终端的换行符差异:

示例代码:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    var inputFile *os.File
    var err error

    // 根据系统选择设备文件
    if isWindows() {
        inputFile, err = os.Open("CON")
    } else {
        inputFile, err = os.Open("/dev/tty")
    }
    if err != nil {
        fmt.Printf("打开终端失败:%v\n", err)
        return
    }
    defer inputFile.Close()

    reader := bufio.NewReader(inputFile)
    fmt.Print("请输入内容:")
    line, err := reader.ReadString('\n')
    if err != nil {
        fmt.Printf("读取输入失败:%v\n", err)
        return
    }
    // 处理Git Bash中的换行符(移除可能的\r)
    line = strings.TrimSuffix(line, "\r\n")
    line = strings.TrimSuffix(line, "\n")
    fmt.Printf("你输入的内容是:%s\n", line)
}

func isWindows() bool {
    return os.PathSeparator == '\\' && os.PathListSeparator == ';'
}

方法3:判断Git Bash环境并适配

通过环境变量MSYSTEM判断当前是否处于Git Bash环境,若是则直接使用os.Stdin而非CON设备:

示例代码片段:

func main() {
    var inputFile *os.File
    var err error

    if isWindows() {
        // 检查是否是Git Bash环境
        if os.Getenv("MSYSTEM") != "" {
            inputFile = os.Stdin
        } else {
            inputFile, err = os.Open("CON")
        }
    } else {
        inputFile, err = os.Open("/dev/tty")
    }
    // 后续读取逻辑同方法2
}

内容的提问来源于stack exchange,提问作者Kevin Zhou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:30:39