Git及Github相关生态的介绍与使用

6/8/2021 GitGit-LFSGit-HooksGithubGithub-ActionGithub-PageGitea

# 1. Git和Github生态

# 1.1 Git与Github简介

Git是一个开源的版本控制软件,具体功能包括记录文件的所有历史变化、随时恢复到任何一个历史状态、多人协作开发或修改....Github是全球最大的社交编程及代码托管网站,用于托管各种Git库,分为私有仓库和公开仓库两种类型。

二者的关系:Git是版本控制软件,Github是项目代码托管的平台,借助Github来管理项目代码。

# 1.2 Git基本工作流程

# 1.2.1 Git核心概念

Git 最核心的一个概念就是工作流。

  • 工作区(Workspace)是电脑中实际的目录。
  • 暂存区(Index)类似于缓存区域,临时保存你的改动。
  • 仓库区(Repository),分为本地仓库和远程仓库。
Git的核心概念

# 1.2.2 Git提交代码基本步骤

使用Git向远程Github仓库提交代码主要有以下三步:

  • Step1:git add从工作区提交到暂存区
  • Step2:git commit从暂存区提交到本地仓库
  • Step3:git push从本地仓库提交到远程仓库
Git提交代码基本步骤

# 1.3 Git提交及版本发布规范

# 1.3.1 Git提交规范

如果一次修改涉及多个功能点,请分开多次提交,提交时必须写语义化注释,注释首行简明扼要说明本次提交内容。

方案一:业界主流版本(建议)

  • feat: 新功能、新特性
  • fix: 修改 bug
  • perf: 更改代码,以提高性能(在不影响代码内部行为的前提下,对程序性能进行优化)
  • refactor: 代码重构(重构,在不影响代码内部行为、功能下的代码修改)
  • docs: 文档修改
  • style: 代码格式修改, 注意不是 css 修改(例如分号修改)
  • test: 测试用例新增、修改
  • build: 影响项目构建或依赖项修改
  • revert: 恢复上一次提交
  • ci: 持续集成相关文件修改
  • release: 发布新版本
  • workflow: 工作流相关文件修改
  • chore: 其他修改(不在上述类型中的修改)

方案二:中文简化版本

  • 新增:表示新增模块,如 新增:用户管理模块,新增requireJS模块。
  • 更新:表示模块功能更新 如 更新:用户管理模块,数据库删除调整为标记删除。
  • 修复:表示修复Bug,如果有对应的issue,需要使用关联关闭,如 修复:用户管理用户名搜索失效。
  • 删除:表示删除功能或模块,如 删除:用户管理模块的积分查看。
  • 升级:表示第三方库升级,如 升级:jQuery从1.8.1提升至2.0.1,升级:Jfinal从2.5升级至3.0。
  • 重构:不影响功能的前提下,调整代码结构文件布局,如 重构:微信消息功能。

# 1.3.2 版本发布规范

发布软件版本时,版本号应采用字母"v"+语义化版本规范,详见:https://semver.org/lang/zh-CN/ (opens new window)

对于未正式发行的版本,后加"-"符号和tag。 如 v0.1.0-alpha

tag表示了此版本软件处于的开发阶段,可选的tag和对应含义如下:

* alpha  自测版本
* beta   外部测试版本
* rc     发行候选版本,可能有rc1,rc2等版本
* stable 稳定版,经过长期正式使用仍然稳定的版本
1
2
3
4

# 1.4 Github基本介绍

# 1.4.1 Github核心概念

  • 仓库(Repository):仓库用来存放项目代码,每个项目对应一个仓库,多个开源项目则有多个仓库。
  • 收藏(Star):收藏项目,方便下次查看。
  • 复制克隆项目(Fork)&& 发起请求(Pull Request):在原项目的主分支上又建立了一个分支,你可以在该分支上任意修改,如果想将你的修改合并到原项目中时,可以pull request,这样原项目的作者就可以将你修改的东西合并到原项目的主分支上去。
  • 关注(Watch):关注项目,当项目更新可以接收到通知。
  • 事务卡片(Issue):发现代码BUG,但是目前没有成型代码,需要讨论时使用。

# 1.4.2 Github开选择源许可证

世界上最流行的六种开源许可证——MPL (opens new window)GPL (opens new window)BSD (opens new window)MIT (opens new window)Apache (opens new window)LGPL (opens new window),开源许可证详解见:https://choosealicense.com/licenses (opens new window)

如何选择适合的开源许可证?

如何选择适合的开源许可证

简单点来说,就是:

# 1.4.3 Github Action简介

GitHub Actions 是在 GitHub Universe 大会上发布的,被 Github 主管 Sam Lambert 称为 “再次改变软件开发” 的一款重磅功能。于 2018 年10月推出,内测了一段时间后,于 2019年11月13日正式上线。

  • GitHub 会提供一个以下配置的服务器做为 runner(2-core CPU、7 GB of RAM memory、14 GB of SSD disk space),免费额度最多可以同时运行 20 个作业。

  • 很多操作在不同项目里面是类似的,完全可以共享。GitHub 也注意到了这一点,于是它允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。

  • GitHub Actions 中文文档:GitHub Actions Documentation (opens new window)

  • GitHub Actions 官方市场:Actions Marketplace (opens new window)

GitHub Actions 有一些自己的术语:

  • workflow(工作流程):持续集成一次运行的过程,就是一个 workflow。
  • job (任务):一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务。
  • step(步骤):每个 job 由多个 step 构成,一步步完成。
  • action (动作):每个 step 可以依次执行一个或多个命令。

# 1.4.4 Github Page简介

GitHub Page 是GitHub 提供给用户用来展示个人或者项目主页的静态网页系统。也就是说我们可以把项目代码写好后上传GitHub,然后利用GitHub Page为这个项目生成一个静态页面,别人通过网址可以访问我们的页面。

使用步骤如下:

  • 新建仓库(仓库名必须是用户名.github.io
  • 在仓库下新建index.html文件,并编写内容。
  • 在浏览器输入:https://用户名.github.io即可访问我们的Github Page

注:Github Page 仅支持静态网页,仓库里面是.html文件,这个文件未必需要自己手动编写,可以借助Gitbook之类的生成工具进行构建,详见我的另一篇博客:搭建Gitbook并通过Git推送部署 (opens new window)

# 1.4.5 Github项目榜单推荐

可以通过Github Trending寻找优秀的热门项目,除此之外,另提供几个收集性质的项目如下:

# 1.5 Github常见问题

# 1.5.1 Github条件检索

搜索条件:stars:             举例:stars:>=500,匹配收藏数量超过500的项目
搜索条件:forks:             举例:forks:>=500,匹配分支数量超过500的项目
搜索条件:language:          举例:language:javascript,匹配以javascript作为开发语言的项目
搜索条件:Awesome            举例:Awesome windows,检索有关windows的工具软件
1
2
3
4

注:Awesome 已经成为不少 GitHub 工具软件项目喜爱的命名,所以可以用它来检索,并不是它本身有这个功能。

# 1.5.2 Github下载单个文件

需求情景:有时我们只需下载Github上的单个文件,而无需下载整个仓库。

操作方法:跳转到欲下载文件的具体页面,右键“Raw”,再点击“链接另存为...”。

# 1.5.3 使用VSCode界面查看Github的代码

项目地址:https://github.com/conwnet/github1s (opens new window)

使用方式:直接在项目地址的github后面加上1s即可,例如https://github1s.com/Sunnyyoung/WeChatTweak-macOS.git

# 1.5.4 使Fork的项目与原作者自动更新

可以借助一个名为pull的Github app来实现,它每隔几小时将自动拉动请求使您的Fork与上游保持最新状态。

注:安装完的Github app可以在Settings——Developer settings——Applications里找到

# 1.5.5 获取 Github 的 Token

Step1:点击右上角头像——点击 Settings——点击底下的 Deverloper settings

Step2:点击 Personal Access Token ——再点击 Generate new token——填写信息,勾选 repo,拉到最下点击 Generate token——保存生成的 Token(只能看到这一次)

获取Github的Token

# 1.5.6 访问Github受到墙干扰的问题

Github受中国大陆的GFW干扰,时而能访问,时而访问不到,建议使用梯子。如果实在没有梯子,可以尝试以下办法,但效果都不是很好。

方式一:使用GitHub加速的Chrome插件、Tempermonkey脚本

方式二:通过绕过DNS解析,直接在本地绑定host

  • Step1:打开 http://tool.chinaz.com/dns (opens new window),输入github.com,选择一个TTL值较小的IP地址(如:192.30.253.113)

  • Step2:打开电脑的 C:\Windows\System32\drivers\etc 目录,找到hosts文件,在文件末追加:

    192.30.253.113 github.com,
    151.101.109.194 github.global.ssl.fastly.Net
    
    1
    2
  • Step3:刷新DNS缓存,在cmd命令行中输入ipconfig /flushdns

方式三:使用镜像站进行下载

  • 在项目地址的github.com后面加上.cnpmjs.org即可,例如https://github.com.cnpmjs.org/Sunnyyoung/WeChatTweak-macOS.git

# 1.5.7 Github里的图片无法正常显示

问题描述:Github里的图片无法正常显示,点击图片显示“找不到 raw.githubusercontent.com 的网页”错误描述信息。

原因分析:Github的raw文件读取地址遭受DNS污染,导致文件下载困难。

解决方法:

  • Step1:打开目录:C:/Windows/System32/drivers/etc/
  • Step2:找到hosts文件,使用管理员模式打开记事本,在其尾部添加:151.101.0.133 raw.githubusercontent.com
  • Step3:保存hosts文件,重启计算机

基本常识:

  • DNS污染:网域服务器缓存污染(DNS cache pollution),又称域名服务器缓存投毒(DNS cache poisoning),是指一些刻意制造或无意中制造出来的域名服务器数据包,把域名指往不正确的IP地址。
  • hosts:它是一个没有扩展名的系统文件,其基本作用就是将一些常用的网址域名与其对应的 IP 地址建立一个关联的“数据库”。当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从hosts文件中寻找对应的 IP 地址,一旦找到,系统就会立即打开对应网页,如果没有找到,则系统会将网址提交 DNS 域名解析服务器进行 IP 地址的解析。

# 1.5.8 提取Github项目的所有版本变更日志

需求情景:某些开源项目的迭代非常快,想要把它的版本变更日志爬取下来,用一个html进行展现,以关注其最新动态。

提取所有版本变更日志的脚本由GPT-4编写,代码如下:

# -*- coding: utf-8 -*-

import markdown
import requests
import re
from yattag import Doc
from datetime import datetime


def get_release_notes(user, repo):
    page = 1
    releases_info = []
    while True:
        url = f"https://api.github.com/repos/{user}/{repo}/releases?page={page}"
        response = requests.get(url)
        data = response.json()
        if not data:
            break
        for release in data:
            version = release['tag_name']
            date = release['published_at']
            # 解析和格式化日期和时间
            date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
            date = date.strftime("%Y-%m-%d %H:%M:%S")
            notes = release['body']
            # 去除 "Full Changelog" 部分
            if '**Full Changelog**' in notes:
                notes = notes.split('**Full Changelog**')[0]
            # 去除所有空行
            notes = '\n'.join([line for line in notes.split('\n') if line.strip() != ''])
            # 将链接替换为 "#编号" 的格式,并添加超链接
            notes = re.sub(rf'https://github.com/{user}/{repo}/pull/(\d+)',
                           rf'[#\1](https://github.com/{user}/{repo}/pull/\1)', notes)
            releases_info.append({
                'version': version,
                'date': date,
                'notes': notes
            })
        page += 1
    return releases_info


def generate_html(data, html_title, output_path):
    doc, tag, text = Doc().tagtext()

    with tag('html'):
        with tag('head'):
            with tag('style'):
                text('''
                body {
                    font-family: Arial, sans-serif;
                    margin: 0;
                    padding: 0;
                    background-color: #f0f0f0;
                    display: flex;
                }
                .sidebar {
                    width: 12%;
                    padding: 20px;
                    background-color: #fff;
                    border-right: 1px solid #ddd;
                    height: 100vh;
                    position: fixed;
                    overflow: auto;
                }
                .sidebar h2 {
                    margin-top: 0;
                }
                .sidebar ul {
                    list-style-type: none;
                    padding-left: 0;
                }
                .sidebar li {
                    margin-bottom: 10px;
                }
                .sidebar a {
                    color: #337ab7;
                    text-decoration: none;
                    transition: color 0.3s ease;
                }
                .sidebar a:hover {
                    color: #23527c;
                }
                .container {
                    width: 85%;
                    margin-left: 15%;
                    padding: 20px;
                }
                .release {
                    background-color: #fff;
                    border-radius: 5px;
                    padding: 20px;
                    margin-bottom: 20px;
                }
                .release h2 {
                    margin-top: 0;
                }
                .release p {
                    margin-bottom: 10px;
                }
                .release a {
                    color: #337ab7;
                    text-decoration: none;
                }
                .release a:hover {
                    color: #23527c;
                    text-decoration: underline;
                }
                ''')
        with tag('body'):
            with tag('div', klass='sidebar'):
                with tag('h2'):
                    text('版本目录')
                with tag('ul'):
                    for release in data:
                        with tag('li'):
                            with tag('a', href=f"#{release['version']}"):
                                text(release['version'])
            with tag('div', klass='container'):
                with tag('h1'):
                    text(html_title)
                for release in data:
                    with tag('div', klass='release'):
                        with tag('h2', id=release['version']):
                            text(f"版本:{release['version']}")
                        with tag('p'):
                            text(f"发布日期:{release['date']}")
                        with tag('div'):
                            doc.asis(markdown.markdown(release['notes'], extensions=['markdown.extensions.extra']))

    html = doc.getvalue()

    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(html)


if __name__ == '__main__':
    # 配置信息
    github_user = 'logspace-ai'
    github_repo = 'langflow'
    html_title = 'Langflow更新日志'
    output_path = './langflow_releases_info.html'
    # 爬取数据并生成页面
    releases_info = get_release_notes(github_user, github_repo)
    generate_html(releases_info, html_title, output_path)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

页面效果:

提取Github项目的所有版本变更日志

# 1.6 生成Github贡献统计图

# 1.6.1 使用githubchart-api生成Github贡献图

项目简介:将Github贡献图表嵌入为图像,支持修改配色。

项目地址:https://github.com/2016rshah/githubchart-api (opens new window)

这个API的使用很简单,使用img标签引用即可

<img src="http://ghchart.rshah.org/用户名" />
1

也支持修改配色,只需在用户名前加上所需的十六进制颜色代码即可。例如,如果想要一个基于十六进制颜色的蓝色主题图表#409ba5

<img src="http://ghchart.rshah.org/409ba5/用户名" />
1

示例:https://ghchart.rshah.org/409ba5/Logistic98

githubchart-api

# 1.6.2 使用Green-Wall生成Github贡献图

项目描述:GitHub 贡献图生成器。

项目地址:https://github.com/Codennnn/Green-Wall (opens new window) 官方体验地址:https://green-wall.vercel.app (opens new window)

在 GitHub Username 的输入框处输入你的Github账号,点击Generate即可生成历年的Github贡献图。

Green-Wall

# 1.6.3 使用GitHubPoster生成多平台贡献图

项目描述:一个基于Python的生成Github热力图项目,目前支持的平台有:Strava (opens new window)开心词场 (opens new window)扇贝 (opens new window)Nintendo Switch (opens new window)GPX (opens new window)多邻国 (opens new window)Issue (opens new window)Twitter (opens new window)YouTube (opens new window)Bilibili (opens new window)GitHub (opens new window)GitLab (opens new window)Kindle (opens new window)WakaTime (opens new window)Dota2 (opens new window)

[1] 克隆项目并安装依赖

依次输入以下三条命令克隆项目并安装依赖,如果安装依赖有报错请自行解决。

$ git clone https://github.com/yihong0618/GitHubPoster.git
$ cd GitHubPoster
$ pip install -r requirements.txt
1
2
3

[2] GitHubPoster的基本使用

不同平台的命令参数有所不同,可以使用python cli.py <type> --help命令查看具体参数,详见 GitHubPoster README (opens new window)。以下以 Leetcode 平台为例,生成方块热力图,其他平台的用法这里就不赘述了。

Step1:查看命令参数

先使用以下命令查看一下 Leetcode 平台的命令参数。

$ python cli.py leetcode --help
1

命令参数

Step2:获取Cookie

  • Chrome浏览器打开 Leetcode官网 (opens new window) 并登录账号
  • 右键“检查”,打开开发者工具,点击Network并按Ctrl+R刷新页面,点击all/资源复制其Cookie。

Step3:运行项目生成方块热力图

切换到GitHubPoster的安装目录执行生成命令,注意需要把${}标识的地方换成自己的配置(不带${}

$ cd GitHubPoster
$ python cli.py leetcode --cookie ${leetcode_cookie} --year ${year} --me ${name} --cn
1
2

生成的热力图在/root/GitHubPoster/OUT_FOLDER目录下,是一个svg文件。

# 1.6.4 使用github-readme-stats生成Github账号统计

项目描述:为Github自述文件动态生成的统计信息。

项目地址:https://github.com/anuraghazra/github-readme-stats (opens new window)

github-readme-stats

将其复制粘贴到Mrakdown内容中即可,需要将?username=的值修改为你自己的 GitHub 用户名。

![Anurag's GitHub stats](https://github-readme-stats.vercel.app/api?username=Logistic98&show_icons=true)
1

注:可用排名为 S+(前 1%)、S(前 25%)、A++(前 45%)、A+(前 60%)和 B+(所有人)。这些值是通过使用提交、贡献、问题、星级、拉取请求、关注者和拥有的存储库的 累积分布函数 (opens new window) 来计算的,可在 src/calculateRank.js (opens new window) 研究该实现。

# 2. Git与Github使用

# 2.1 本地搭建Git环境

# 2.1.1 下载安装Git

Git下载安装:Git官网 (opens new window)(墙内下载极慢,建议挂梯子下载),安装过程中一路next即可,安装成功后桌面右键单击出现Git GUI Here以及Git Bash Here

由于IDE一般都会集成Git工具,因此一般不需要单独安装Git可视化工具,如果想要安装的话,可以使用SourceTree。

SourceTree

# 2.1.2 生成并设置SSH KEY

本地Git仓库和远程仓库之间的传输是通过SSH加密的。

Step1:生成SSH KEY

[1] win环境

先看一下C:\Users\xxx有没有.ssh目录,有的话再看下里面有没有id_rsaid_rsa.pub这两个文件,如果没有就通过下面命令创建:

$ ssh-keygen -t rsa -C "[email protected]"                        // 生成SSH KEY
1

然后一路回车,这时你就会在用户下的.ssh目录里找到id_rsaid_rsa.pub这两个文件。

[2] mac环境

$ ssh-keygen -t rsa -C "[email protected]"     
$ ls -l /root/.ssh
$ cat /root/.ssh/id_rsa.pub
$ cat /root/.ssh/id_rsa
1
2
3
4

生成SSH-KEY

Step2:设置SSH KEY

  • Github:登录 Github ,找到右上角的图标,打开点进里面的 Settings ,再选中里面的 SSH and GPG KEYS ,点击右上角的 New SSH key,然后 Title 里面随便填,再把刚才 id_rsa.pub 里面的内容复制到 Title 下面的 Key 内容框里面,最后点击Add SSH key,这样就完成了SSH Key 的加密。
  • Gitea:登录Gitea,找到右上角的图标,找到设置,再选中 SSH/GPG 密钥选项卡,增加密钥,然后密钥名称随便填,再把刚才 id_rsa.pub 里面的内容复制到密钥内容框里面,最后点击增加密钥,这样就完成了SSH Key 的加密。

# 2.1.3 Git设置代理

由于Github的服务器在国外,虽然没有被 GFW 完全的墙掉,但也经常会受一些干扰,导致速度极慢甚至超时。强烈建议在电脑装一下诸如Clash、SSR的翻墙软件,然后给Git设置代理,这样访问速度就很快了。

//设置全局代理
$ git config --global https.proxy http://127.0.0.1:1080
$ git config --global https.proxy https://127.0.0.1:1080

//使用socks5代理的 例如ss,ssr。1080是windows下ss的默认代理端口,mac下不同,或者有自定义的,根据自己的改
$ git config --global http.proxy socks5://127.0.0.1:1080
$ git config --global https.proxy socks5://127.0.0.1:1080

//只对github.com使用代理,其他仓库不走代理
$ git config --global http.https://github.com.proxy socks5://127.0.0.1:1080
$ git config --global https.https://github.com.proxy socks5://127.0.0.1:1080

//取消github代理
$ git config --global --unset http.https://github.com.proxy
$ git config --global --unset https.https://github.com.proxy

//取消全局代理
$ git config --global --unset http.proxy
$ git config --global --unset https.proxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

说明:

  • 查看已设置的 git 配置:git config --list
  • 如果在命令行使用git clone时报Failed to connect to github.com port 443: Timed out的错误,这是Git设置的代理有问题,检查相关设置是否正确(一般是代理软件换了端口,而Git的代理配置里没有及时更改)

# 2.2 使用Git提交代码并推送Github

# 2.2.1 Git的初次提交

Step1:在Github创建仓库,然后记录下来仓库的URL。

Step2:设置邮箱、连接远程仓库、记住密码、首次提交推送的命令如下:

[1] 设置用户名和邮箱
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
[2] 连接到远程仓库并设置记住用户名和密码
git remote add origin URL # 连接到远程仓库并创建别名
git config --global credential.helper store # 设置自动记住用户名和密码(第一次push会被记住,后续无需再输入)
[3] 解决使用git add命令时报错LF will be replaced by CRLF的问题
git config auto.crlf true
[4] 将项目从本地提交到仓库
git init # 创建git工作区
git add . # 提交所有文件到暂存区
git status # 查看git状态
git commit -m 'description' # 提交到仓库,''内的是描述信息
[5] 将代码推送至远程仓库
git pull origin master --allow-unrelated-histories # 取回远程仓库分支的更新,再与本地的分支合并
git push -u origin master # 将本地仓库推送至远程仓库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意事项:

  • 用户名和邮箱设置,要根据Github的注册信息来填写,可以在Github仓库主页显示谁提交了该文件。
  • git init之后,在文件夹内生成 .git 文件(如果没有,则点击资源管理器的查看,勾选“隐藏的项目”)

# 2.2.2 Git的后续使用

完成初次部署后,后续使用就比较简单了,常用的有以下几个命令:

git config auto.crlf true # 解决使用git add命令时报错LF will be replaced by CRLF的问题
git add . # 提交所有文件到暂存区
git status # 查看git状态
git commit -m 'description' # 提交到仓库,''内的是描述信息
git pull origin master # 取回远程仓库分支的更新,再与本地的分支合并
git push origin master # 将本地仓库推送至远程仓库
1
2
3
4
5
6

注:我们可以把一些常用的命令组合写成shell脚本,这样就不用每次都一条条命令输入了,直接在Git Bash里执行bash xxx.sh即可。

# 2.2.3 Git的分支操作

git branch dev               # 创建分支
git checkout dev             # 切换分支
git branch -a                # 查看分支
git push origin dev          # 推送分支
git branch -D dev            # 删除本地分支
git push origin --delete dev # 删除远程分支
1
2
3
4
5
6

实际场景示例:

[1] 假设我们现在在dev分支上刚开发完项目并推送了代码,测试通过后,想将dev分支合并到master分支。

Step1:首先切换到master分支上
git checkout master

Step2:如果是多人开发的话,需要先把远程master上的最新代码pull下来,如果是自己一个人开发就没有必要了
git pull origin master

Step3:然后把dev分支的代码合并到master上
git merge dev

Step4:最后把master分支上合并完的代码推送到远程仓库上
git push origin master

Step5:最后回到dev分支上
git checkout dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14

注:如果当前dev分支有修改了的内容,无法切换分支,可以先暂存起来(git stash),合并完分支之后,再保存回去(git stash apply)。

[2] git pull 时出现冲突导致无法 merge 的问题。

error: Your local changes to the following files would be overwritten by merge:
        xxx/src/main/resources/application-dev.yml
        xxx/src/main/resources/application.yml
Please, commit your changes or stash them before you can merge.
Aborting
1
2
3
4
5

解决办法:

Step1:暂存本地修改 git stash
Step2:拉取代码 git pull
Step3:将暂存的修改内容保存回去(会有冲突项) git stash apply
Step4:手动解决冲突文件
Step5:手动解决完冲突之后,再add、commit、push一下
1
2
3
4
5

[3] 回到某个分支的历史版本获取文件

git checkout 分支名
git log --pretty=oneline
git checkout 版本ID
1
2
3

# 2.3 Git常见情形解决方案

# 2.3.1 撤销本地及远程提交

有时我们会误提交某些代码,或者发现代码有bug需要修复。

[1] 撤销本地提交(未push到远程仓库)

保留当前代码,只是撤回本地提交记录

$ git reset --soft HEAD^   // 撤回到上个版本的提交记录
$ git reset --soft HEAD~3   // 撤回到3个版本前的提交记录
1
2

注:如果只是想修改一下上次提交的注释,使用以下命令会进入vim编辑器,修改注释完毕后保存即可。

$ git commit --amend
1

2)不保留当前代码,退回之前的某个版本

$ git log  // 查看日志,找到要恢复版本的版本代号
$ git reset <版本代号>  // reset指定版本的版本代号即可还原
1
2

[2] 撤销远程提交(已push到远程仓库)

$ git log                             // 查看Git的commit记录
$ git reset --hard <版本代号>          // 回推到没问题的版本
$ git push origin <分支名> --force    // 强制push到对应的分支并覆盖
1
2
3

# 2.3.2 清除旧仓库的历史记录

把旧项目提交到Git上,但是会有一些历史记录,这些历史记录中可能会有项目密码等敏感信息,可以通过如下操作删除这些历史记录,形成一个全新的仓库,并且保持代码不变。

clear_commit_history.sh

git checkout --orphan latest_branch
git add -A
git commit -am "commit message"
git branch -D master
git branch -m master
git push -f origin master
1
2
3
4
5
6

# 2.3.3 移除版本控制并添加忽略

需求情景:之前已经将代码加入了Git版本控制,后续添加进.gitignore之后,原本已经加进版本控制的目录及文件依然存在,想要将其移除。

解决办法:使用命令git rm --cached xxx命令,然后将该文件写入.gitignore中即可。

$ git rm -r --cached dirname     // 移除目录的版本控制
$ git rm --cached filename       // 移除文件的版本控制
1
2

注:该命令表示从git仓库中将文件移除,不再进行版本控制,但保留工作区的该文件。

# 2.3.4 往Github推送大于100M的大文件

GitHub是存在单次上传文件的大小限制的,直接上传一个大于100M的文件(比如深度学习的模型文件一般都很大)就会报错。

这时就需要使用GitHub的一个插件进行上传,该插件就是:Git Large File Storage (LFS) (opens new window)

Step1:下载安装LFS客户端

$ wget https://github.com/git-lfs/git-lfs/releases/download/v3.4.0/git-lfs-darwin-amd64-v3.4.0.zip
$ unzip git-lfs-darwin-arm64-v3.4.0.zip
$ cd git-lfs-3.4.0
$ ./install.sh
1
2
3
4

Step2:开启大文件上传并开启跟踪

$ git lfs install             // 开启大文件上传
$ git lfs track "*.tar"       // 跟踪指定后缀名的文件(把*.tar换成自己的大文件后缀)
$ git add .gitattributes      // 添加属性跟踪文件
1
2
3

Step3:先把.gitattributes文件推送Github

如果已经 git add了大文件,需要先通过git log和git reset回退到无大文件的版本,先把.gitattributes文件推送到Github

$ git add .gitattributes 
$ git commit -m "set large file upload"
$ git push origin master
1
2
3

Step4:再把项目(包含大文件即可)推送到Github

$ git add . 
$ git commit -m "commit message"
$ git push origin master
1
2
3

# 2.3.5 将一个项目同时推送多个Git远程仓库

需求情景:Git远程仓库常见的的有Github、Gitlab、Gitea、Gitee等,有时我们需要将一个项目同时推送到多个远程仓库,可通过以下方式来实现(前提是共用同一个ssh-key)。

$ git remote set-url --add origin https://[email protected]:user/test-project.git      // 另一个远程仓库的地址(https的那个)
1

其实质是改动了.git目录下的config文件,产生了多个推送url,如果哪个远程仓库不想推送了,就删掉它即可。

[remote "origin"]
	url = https://gitea.your.domain/user/test-project.git
	fetch = +refs/heads/*:refs/remotes/origin/*
	url = [email protected]:user/test-project.git
1
2
3
4

# 2.4 Git常见报错问题

1)使用git pull origin master命令报错:fatal:refusing to merge unrelated histories

  • 错误原因:如果合并了两个不同的开始提交的仓库,在新的git会发现这两个仓库可能不是同一个,为了防止开发者上传错误,于是就出现了此提示。

  • 解决办法:如我在Github新建一个仓库,写了License,然后把本地一个写了很久仓库上传。这时会发现 github 的仓库和本地的没有一个共同的 commit 所以 git 不让提交,认为是写错了 origin ,如果开发者确定是这个 origin 就可以使用 --allow-unrelated-histories 告诉 git 允许不相关历史合并

2)使用git push origin master命令报错:error:failed to push some refs to URL

  • 错误原因:直接在 GitHub 上修改后,内容已经和本地不一致了,必须要合并(merge)
  • 解决办法:先使用git pull origin master命令下载到本地并合并,自动弹出的vim编辑器(按 i 进行编辑,说明为什么合并,可选择不修改,ESC进入命令行模式然后输入:wq退出),再git push origin master

3)使用git add .命令报错:warning: LF will be replaced by CRLF

  • 错误原因:在Unix系统中,行尾用换行(LF)表示。在窗口中,用回车(CR)和换行(LF)(CRLF)表示一行。当您从unix系统上载的git中获取代码时,它们将只有LF。
  • 解决办法:如果您是在Windows计算机上工作的单个开发人员,并且您不关心git自动将LF替换为CRLF,则可以通过在git命令行中运行git config core.autocrlf true来关闭此警告。

4)git总是弹出git login弹框页面的问题

  • 情景描述:每次push到远程的时候总会出现弹框,要求输入账号和密码,而输入账号和密码,明明是对的,却提示登录失败。
  • 出现原因:会弹出这个登录弹框页面,是因为是执行过git config --global credential.helper manager 这个命令,你可以通过: git config --list 来查看,里面有一行credential.helper=manager
  • 解决办法:输入git config --system --unset credential.helper命令即可,再使用git config --list 来查看,里面配置改为了credential,helper=store,输入一次账号密码就可记住了。

5)Git Bash Here终端中文乱码问题

  • 临时解决办法:对窗口右键->Options->Text->Locale改为zh_CN,Character set 改为GBK。键入exit退出关闭再打开即可。
  • 说明:强烈不建议这么做,因为大部分代码都是utf-8的,这么设置会导致那些代码出问题,干脆就别用中文了。

6)重新搭建服务端git之后,配置完密钥仍然git push报错:has changed and you have requested strict checking. Host key verification failed.

  • 解决方案:打开.ssh目录,删除known_hostsknown_hosts.old ,重新生成即可。

7)git push时报错 error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8)

  • 解决方案:增加git缓冲区大小

    $ git config --global http.postBuffer 524288000
    
    1

8)git push时报错:fatal: unable to access 'xxx': Connection timed out after 300040 milliseconds

  • 出错原因:这是由于设置了代理,但是现在代理不可用了导致的。

  • 解决方案:重置一下代理设置即可解决。

    $ git config --global --unset http.proxy
    
    1

9)git push时报错:HTTP/2 stream 1 was not closed cleanly before end of the underlying stream

  • 出错原因:git 默认使用的通信协议出现了问题。

  • 解决方案:将默认通信协议修改为 http/1.1 解决该问题

    $ git config --global http.version HTTP/1.1
    
    1

13)git push -f 报错:remote: GitLab: You are not allowed to force push code to a protected branch on this project.

  • 出错原因:该分支是受保护的分支,禁止强制推送。

  • 解决方案:如果你是该项目的拥有者,则拥有权限将其去除分支保护。

    登录到你的 GitLab 项目
    转到 "Settings"(设置) -> "Repository"(仓库)
    找到 "Protected Branches"(受保护分支)
    点击你想解除保护的分支旁边的 "Unprotect"(解除保护)按钮
    
    1
    2
    3
    4

# 3. Git服务端及Gitea搭建

# 3.1 服务器搭建Git环境

# 3.1.1 安装配置Git

Step1:下载安装Git服务器

$ apt-get install git
1

Step2:验证是否安装成功

$ git --version
1

若显示版本信息则说明安装成功。

# 3.1.2 创建用户并赋予权限

Step1:创建git用户

$ adduser git
1

用户名以git为例,根据提示设置密码。

Step2:赋予git用户权限

$ chmod 740 /etc/sudoers
$ nano /etc/sudoers
1
2

root ALL=(ALL:ALL) ALL这一行下面添加git ALL=(ALL:ALL) ALL

# User privilege specification
root    ALL=(ALL:ALL) ALL
git     ALL=(ALL:ALL) ALL
1
2
3

保存退出后,修改回文件权限

$ chmod 440 /etc/sudoers
1

Step3:关闭git用户的shell权限

考虑到安全因素,需要禁止git用户ssh登录服务器,设置后git用户可以通过ssh正常使用git服务,但无法登录shell。

$ nano /etc/passwd
1

将最后一行的bash处改为git-shell

git:x:1001:1001:,,,:/home/git:/bin/bash 改成 git:x:1001:1001:,,,:/home/git:/bin/git-shell
1

# 3.1.3 初始化git仓库并配置SSH

Step1:初始化git仓库

$ cd /home/git                    //切换到git用户目录
$ mkdir gitbook.git                  //创建仓库目录,以gitbook.git为例
$ cd gitbook.git                     //进入仓库目录
$ git init --bare                 //使用--bare参数初始化为裸仓库,这样创建的仓库不包含工作区
1
2
3
4

Step2:查看公钥

打开本地的 git bash,输入以下命令查看公钥(前提是本地已经配好了git环境并完成初始化),复制公钥

$ cat ~/.ssh/id_rsa.pub
1

Step3:配置SSH

$ cd /home/git                   //切换到git用户目录
$ mkdir .ssh                     //创建.ssh目录
$ cd .ssh                        //进入.ssh目录
$ nano authorized_keys           //将本地的公钥复制到authorized_keys文件里
1
2
3
4

Step4:用户组管理

修改/home/git/gitbook.git目录的用户组权限为git:git

$ sudo chown git:git -R /home/git/gitbook.git
1

修改后执行下列命令后再查看

$ ls -l /home/git
1

# 3.1.4 本地连接远程仓库

打开本地的git bash,检出仓库并设置记住用户名和密码,然后我们就可以使用git进行版本控制了,git无需手动设置开机自启。

Step1:本地检出仓库

$ git clone ssh://git@ip:port/home/git/gitbook.git
1

Step2:设置记住用户名和密码

$ git config --global credential.helper store
1

# 3.2 Git Hooks自动部署

# 3.2.1 自动部署原理

Git Hooks实际上就是当Git仓库收到最新的push时,将Git仓库接受到的内容复制到服务器上的网站目录内。

# 3.2.2 配置Git Hooks

创建post-receive文件

$ cd /home/git/project.git/hooks     //切换到hooks目录下
$ nano post-receive                  //创建post-receive文件并编辑
1
2

复制下面的内容到post-receive文件中:

#!/bin/bash
GIT_REPO=/home/git/project.git
TMP_GIT_CLONE=/tmp/project
TMP_GIT_COPY=/tmp/project/dist
PUBLIC_WWW=网站根目录
rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_COPY}/* ${PUBLIC_WWW}
1
2
3
4
5
6
7
8
9

保存退出后,赋予其执行权限

$ chmod +x post-receive
1

配置好 Git Hooks 之后,提交Git之后,就会自动执行 post-receive 里的脚本内容,实现自动部署。

# 3.3 Gitea远程仓库基本介绍

# 3.3.1 Gitea远程仓库简介

Gitea (opens new window) 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。 Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。采用 Go 作为后端语言,只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。

Gitea简介

# 3.3.2 为什么选用Gitea

企业级最流行的私有代码仓库是Gitlab, 但Gitlab的资源占用太大了,于是选择了轻量级的Gitea(Gitea内存占用情况如下)。Gitea 支持 MySQL、PostgreSQL、SQLite3 等多种数据库,我这里选择了PostgreSQL数据库。

Gitea内存占用

# 3.4 搭建Gitea远程仓库服务

# 3.4.1 拉取镜像并创建容器

$ mkdir /root/gitea && cd /root/gitea
$ vim docker-compose.yml
1
2

写入 docker-compose.yml 的配置(注意连接信息和挂载路径改成自己的)

version: '3.9'

# 创建自定义网络
networks:
  gitea_network:
    name: gitea_network
    driver: bridge

services:
  ## 数据库服务
  db:
    image: postgres:latest
    container_name: gitea_db
    restart: always
    networks:
      - gitea_network # 加入到gitea_network网络
    ports:
      - 3003:5432
    environment:
      - POSTGRES_USER=gitea # PGSQL默认用户
      - POSTGRES_PASSWORD=my_pgsql_password # PGSQL默认密码
      - POSTGRES_DB=giteadb # PGSQL默认数据库
    volumes:
      - /root/gitea/db:/var/lib/postgresql/data
  #gitea服务
  server:
    image: gitea/gitea:latest
    container_name: gitea_server
    restart: always
    networks:
      - gitea_network # 加入到gitea_network网络
    ports:
      - '3000:3000' # HTTP服务端口
      - '3002:22' # SSH服务器端口
    environment:
      - USER_UID=1000 # 运行容器使用的 UID  UID和GID是用于匿名数据卷挂载,
      - USER_GID=1000 # 运行容器使用的 GID
      - APP_NAME=gitea
      - PROTOCOL=http # 服务使用的访问协议
      - HTTP_PORT=3000 # HTTP 侦听端口 默认为3000
      - SSH_PORT=22 # 克隆 URL 中显示的 SSH 端口
      - DOMAIN=ip:3000 # UI显示的 HTTP克隆URL
      - LANDING_PAGE=explore
      - ROOT_URL=http://ip:3000 # 服务器的对外 URL
      - DB_TYPE=postgres # 数据库类型
      - DB_HOST=db # 数据库连接地址, 使用network形式连接, serverName或者containerName
      - DB_NAME=giteadb # 数据库名称
      - DB_USER=gitea # 数据库连接用户
      - DB_PASSWD=my_pgsql_password # 数据库连接密码
      - DISABLE_REGISTRATION=true # 禁用用户注册,启用后只允许管理员添加用户
      - SHOW_REGISTRATION_BUTTON=false # 是否显示注册按钮
      - REQUIRE_SIGNIN_VIEW=true # 是否所有页面都必须登录后才可访问

    volumes:
      - /root/gitea/server/data:/data
      - /root/gitea/server/conf:/data/gitea/conf
      - /root/gitea/server/config:/etc/config
      - /root/gitea/server/timezone:/etc/timezone:ro
      - /root/gitea/server/localtime:/etc/localtime:ro
    depends_on:
      - db
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

注:我这里出于安全性的考虑,将 REQUIRE_SIGNIN_VIEW 设置为了 true,所有页面都必须登录后才可访问,如果想公开访问,就把它设置成false。

然后拉取镜像并创建容器即可。

$ docker-compose up -d     // 拉取镜像并创建容器
1

# 3.4.2 Gitea的初始化设置

使用Chrome浏览器打开http://ip:3000路径,会显示Gitea初始化的基本设置界面。向导页面会带入 environment 中填写的设置,很多信息不需要进行设置。

其中我们只需要设置管理员账号设置即可(如果不设置管理员,默认第一个注册用户将自动成为管理员,但是在禁止注册的情况下必须设置管理员)。

Gitea初始化设置

# 3.4.3 设置反向代理并开启HTTPS

这时我们使用https://域名打开Gitea时,会显示如下错误,我们需要修改一下Gitea的配置

Gitea反向代理错误

配置文件是容器内的 /data/gitea/conf/app.ini,先前我们已经挂载出来了,只需要修改此配置文件中 ROOT_URL、DOMAIN、 SSH_DOMAIN配置,随后重启Gitea容器即可。

DOMAIN           = 域名
SSH_DOMAIN       = 域名
ROOT_URL         = https://域名/
1
2
3

然后 Nginx 有一个上传文件大小限制,上传大于限制大小的文件会报错,我们把Nginx配置文件里的client_max_body_size属性调大即可,然后重载Nginx配置。

$ vim /usr/local/nginx/conf/nginx.conf  // 修改client_max_body_size属性
$ nginx -s reload
1
2

配置完成之后,我们便可使用https://域名访问我们的Gitea服务了。

# 3.4.4 创建一个仓库并推送项目

Gitea与Github、Gitlab的使用基本一致,这里就不赘述了。

Gitea私有仓库

# 4. 参考资料

[1] 学会Git玩转Github from Bilibili (opens new window)

[2] 如何选择开源许可证?from 阮一峰的网络日志 (opens new window)

[3] 常见的开源许可证介绍 from Github (opens new window)

[4] 掌握3个搜索技巧,在 GitHub 上快速找到实用软件资源 from 少数派 (opens new window)

[5] Git的使用--如何将本地项目上传到Github from 知乎 (opens new window)

[6] git无法pull仓库:refusing to merge unrelated histories报错 from CSDN (opens new window)

[7] git push origin master报错解决办法 from CSDN (opens new window)

[8] git clone时报错Failed to connect to github.com port 443: Timed out from Mentalflow (opens new window)

[9] Git 设置代理 from 简书 (opens new window)

[10] 解决向github提交代码不用输入帐号密码 from segmentfault (opens new window)

[11] git强制覆盖本地代码(与git远程仓库保持一致) from CSDN (opens new window)

[12] github上如何下载单个文件 from CSDN (opens new window)

[13] 对比Git与SVN,这篇讲的很易懂 from segmentfault (opens new window)

[14] GitHub Actions 入门教程 from 阮一峰 (opens new window)

[15] GitHub Actions 部署爬虫并定时发送邮件 from CSDN (opens new window)

[16] GitHub Action一键部署 from Gitbook (opens new window)

[17] 把一切都变成 GitHub svg 海报和 Skyline from Github (opens new window)

[18] Linux升级python至3.x from CSDN (opens new window)

[19] 如何在Debian 10上安装pip from myfreax (opens new window)

[20] git总是弹出git login弹框问题 from CSDN (opens new window)

[21] git仓库删除所有提交历史记录,成为一个干净的新仓库 (opens new window)

[22] git撤销本地提交 - git reset from CSDN (opens new window)

[23] github 上传大文件100MB姿势 from 博客园 (opens new window)

[24] git使用情景2:commit之后,想撤销commit from CSDN (opens new window)

[25] Windows Git Bash Here 中文乱码问题解决 from CSDN (opens new window)

[26] 怎么在博客网站等地方引用 Github 贡献图表 from 羊毛党之家 (opens new window)

[27] error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1) from stackoverflow (opens new window)

[28] .gitkeep是什么? .gitignore和.gitkeep之间的区别(译) from CSDN (opens new window)

[29] 为您的 github 自述文件动态生成的统计信息 from Github (opens new window)

[30] git合并分支 from 简书 (opens new window)

[31] Git - .gitignore怎么忽略已经被版本控制的文件 from CSDN (opens new window)

[32] Git - 将一个项目同时从本地推送到 GitHub 和 Gitee from 博客园 (opens new window)

Last Updated: 4/25/2024, 5:40:47 PM