GitHub 复制克隆命令按钮(fork)

在 GitHub 仓库页面的“代码”按钮之后,添加一个使用“git clone --recurse-submodules ...”命令的一键复制按钮。

当前为 2026-03-16 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name               Github copy clone command button(fork)
// @name:zh-CN         GitHub 复制克隆命令按钮(fork)
// @description        Add a 1-click copy button with the "git clone --recurse-submodules ..." command, after the Code button on the GitHub repository page
// @description:zh-CN  在 GitHub 仓库页面的“代码”按钮之后,添加一个使用“git clone --recurse-submodules ...”命令的一键复制按钮。
// @author             人民的勤务员 <[email protected]>
// @namespace          https://github.com/ChinaGodMan/UserScripts
// @supportURL         https://github.com/ChinaGodMan/UserScripts/issues
// @homepageURL        https://github.com/ChinaGodMan/UserScripts
// @homepage           https://github.com/ChinaGodMan/UserScripts
// @license            MIT
// @match              https://github.com/*
// @icon               https://raw.githubusercontent.com/ChinaGodMan/UserScriptsHistory/main/scriptsIcon/github-commit-viewer.png
// @grant              GM_setClipboard
// @compatible         chrome
// @compatible         firefox
// @compatible         edge
// @compatible         opera
// @compatible         safari
// @compatible         kiwi
// @compatible         qq
// @compatible         via
// @compatible         brave
// @version            2026.3.16.1
// @created            2026-03-16 15:12:45
// ==/UserScript==

(function () {
    'use strict'

    function getCloneCmd() {
        const match = location.pathname.match(/^\/([^/]+)\/([^/]+)(\/|$)/)
        if (!match) return null
        return `git clone --recurse-submodules https://github.com/${match[1]}/${match[2]}.git`
    }

    function copyCloneCmd(cmd) {
        if (!cmd) return
        if (typeof GM_setClipboard === 'function') {
            GM_setClipboard(cmd)
        } else if (navigator.clipboard) {
            navigator.clipboard.writeText(cmd)
        }
        showTip(`Copied: ${cmd}`)
    }

    function showTip(msg) {
        const tip = document.createElement('div')
        tip.textContent = msg
        tip.style.position = 'fixed'
        tip.style.top = '20px'
        tip.style.right = '20px'
        tip.style.background = '#28a745'
        tip.style.color = '#fff'
        tip.style.padding = '8px 16px'
        tip.style.borderRadius = '6px'
        tip.style.zIndex = 9999
        tip.style.fontSize = '16px'
        tip.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)'
        document.body.appendChild(tip)
        setTimeout(() => tip.remove(), 1800)
    }

    function addCopyButton() {
        const cmd = getCloneCmd()
        if (!cmd) return
        const codeBtn = Array.from(document.querySelectorAll('button[class^="prc-Button-ButtonBase-"]')).find(
            btn => ['代码', 'Code'].includes(btn.textContent.trim())
        )
        if (!codeBtn) return
        if (document.getElementById('copy-clone-submodules-btn')) return

        // SVG字符串多行可读
        const svg = `
<svg aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align: text-bottom;">
  <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path>
  <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
        `.trim()

        // 克隆Code按钮
        const copyBtn = codeBtn.cloneNode(true)
        copyBtn.id = 'copy-clone-submodules-btn'

        // 替换内容为SVG
        const contentSpan = copyBtn.querySelector('[data-component="buttonContent"]')
        if (contentSpan) {
            contentSpan.innerHTML = svg
        } else {
            copyBtn.innerHTML = svg
        }

        // 设置title为命令内容
        copyBtn.title = cmd

        // 移除aria-haspopup等下拉相关属性
        copyBtn.removeAttribute('aria-haspopup')
        copyBtn.removeAttribute('aria-expanded')
        copyBtn.removeAttribute('aria-describedby')

        // 绑定复制事件
        copyBtn.addEventListener('click', function (e) {
            e.preventDefault()
            e.stopPropagation()
            copyCloneCmd(cmd)
        })

        // 插入到Code按钮后
        codeBtn.parentNode.insertBefore(copyBtn, codeBtn.nextSibling)
    }

    // 监听页面变化(支持pjax和动态加载)
    const observer = new MutationObserver(addCopyButton)
    observer.observe(document.body, { childList: true, subtree: true })
    addCopyButton()
})()