Python: 版本控制Git

git服务搭建

Gogs

Go语言开发的Git服务器

https://gogs.io/

Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发,并且支持 Go 语言支持的 所有平台,包括 Linux、Mac OS X、Windows 以及 ARM 平台。

安装步骤

1.新建用户
2.下载源码进行编译Compiler/下载预编译二进制文件
3.安装
4.调整配置
5.配置nginx反向代理
6.添加服务Services及开机启动

注意,这里默认你已经安装并配置好了MySQL和nginx,如果没有,请自行查找如何安装和配置这些依赖Dependencies。当然你也可以使用SQLite数据库。

安装

官方文档:https://gogs.io/docs/installation

软件依赖

在安装 Gogs 之前,您需要先安装基本环境

apt install git -y

Mysql安装

# 查看包
apt list  'mariadb*'
#安装
apt install mariadb-server
systemctl start mariadb
#修改绑定端口
vim  /etc/mysql/mariadb.conf.d/50-server.cnf
bind-address            = 0.0.0.0
systemctl restart mariadb

#添加远程用户
mysql
MariaDB [(none)]> create user root@'%' identified by '123456';

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
SHOW GRANTS FOR 'root'@'%';
#grant all on *.* to 'tom'@'%' identified by 'tom';

初始化脚本提高安全性
运行脚本:mariadb-secure-installation  #mysql_secure_installation

设置数据管理员root口令
禁止root远程登录
删除anonymous用户帐号
删除test数据库

Gogs服务以git用户运行

adduser git # useradd git
su - git

wget https://github.com/gogs/gogs/releases/download/v0.13.3/gogs_0.13.3_linux_amd64.tar.gz
tar xf gogs_0.13.3_linux_amd64.tar.gz
cd gogs/

└─$ ll
total 79344
-rwxr-xr-x 1 git git 81220896 Jun  9 09:38 gogs
-rw-r--r-- 1 git git     1054 Jun  9 09:38 LICENSE
-rw-r--r-- 1 git git     6626 Jun  9 09:38 README.md
-rw-r--r-- 1 git git     5385 Jun  9 09:38 README_ZH.md
drwxr-xr-x 7 git git     4096 Jun  9 09:38 scripts

初始化数据库

mysql -uroot -p < scripts/mysql.sql # 其实就是创建了一个gogs的库

# 为gogs库创建mysql用户gogs,并授权
grant all on gogs.* to 'gogs'@'%' identified by 'gogs';
flush privileges;

配置

参考官方文档: https://gogs.io/docs/installation/configuration_and_run

概述

名称 描述
APP_NAME 应用名称,可以改成您的组织或公司名称
RUN_USER 运行应用的用户名称,我们建议您使用 git,但如果您在个人计算机上运行 Gogs,请修改为您的系统用户名称。如果没有正确设置这个值,很可能导致您的应用崩溃

服务器 (server)

名称 描述
HTTP_ADDR 应用 HTTP 监听地址
HTTP_PORT 应用 HTTP 监听端口号
DOMAIN 服务器域名,会影响 SSH clone 地址

ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/

仓库(repository)

名称 描述
ROOT 用户仓库储存根目录,必须为绝对路径,默认为 ~/<user name>/gogs-repositories

数据库(database)

名称 描述
DB_TYPE 数据库类型,可以是 mysql、postgres、mssql 或 sqlite3
HOST 数据库主机地址与端口
NAME 数据库名称
USER 数据库用户名
PASSWD 数据库用户密码

安全 (security)

名称   描述
INSTALL_LOCK 用于指示是否允许访问安装页面(该页面可以设置管理员帐号,因此该选项非常重要)  
SECRET_KEY 全局的加密密钥,务必修改该值以确保您的服务器安全(会在每次安装时自动生成随机字符串)  

默认配置都保存在 conf/app.ini,永远不需要 编辑它。该文件从 v0.6.0 版本开始被嵌入到二进制中。

自定义配置文件。不需要创建,服务启动后会自动创建。

在gogs目录下建立custom/conf/app.ini配置文件

mkdir -p custom/conf
cd custom/conf
touch app.ini

custom/conf/app.ini内容如下

APP_NAME = cici
RUN_USER = git
RUN_MODE = dev
[server]
HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000

[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gogs
USER = gogs
PASSWD = gogs

[security]
INSTALL_LOCK = fal
SECRET_KEY = www.m

启动gogs

cp /home/git/gogs/scripts/systemd/gogs.service /lib/systemd/system/
systemctl enable --now  gogs

└─# systemctl cat  gogs         
# /usr/lib/systemd/system/gogs.service
[Unit]
Description=Gogs
After=syslog.target
After=network.target
After=mariadb.service mysql.service mysqld.service postgresql.service memcached.service redis.service

[Service]
# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
###
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
Type=simple
User=git
Group=git
WorkingDirectory=/home/git/gogs
ExecStart=/home/git/gogs/gogs web
Restart=always
Environment=USER=git HOME=/home/git

# Some distributions may not support these hardening directives. If you cannot start the service due
# to an unknown option, comment out the ones not supported by your version of systemd.
ProtectSystem=full
PrivateDevices=yes
PrivateTmp=yes
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target


└─# ss -ntlp             
State         Recv-Q        Send-Q               Local Address:Port               Peer Address:Port        Process                                        
LISTEN        0             4096                             *:3000                          *:*            users:(("gogs",pid=4957,fd=3)) 

浏览器访问 http://192.168.226.130:3000/install 配置首次运行安装程序

  • 数据库设置
    • 数据库类型:mysql 账号密码等
  • 应用基本设置
    • 应用名称、仓库根目录、域名等
  • 可选设置
    • 服务器和其它服务设置
      • 勾选 禁用 Gravatar 服务,这是头像但要翻墙
    • 管理员帐号设置(可跳转登录页时再填写)
  • 点击 立即运行

跳转到登录页。需要注册第一个用户,这个用户直接成为管理员账户。

git

由来

Linux内核代码需要版本管理工具管理代码,2002年开始,使用的是BitMover公司的BitKeeper这个商用软件。但是Linux社区崇尚的是自由软件相悖。

  • 2005年,Andrew Tridgell对BitKeeper的协议进行逆向工程,BitKeeper作者决定收回无偿使用授权。磋商无果,Linus又找不到合适的版本管理工具,决定自行开发分布式版本管理工具,一个月后,Linux内核代码被Git接管。
  • 2008年,基于WEB使用Git进行版本控制的软件托管服务的网站GitHub上线。
  • 2016年5月9日,11年后,BitKeeper开源,发布在了GitHub上。
  • 2018年6月4日,微软宣布,通过75亿美元的股票交易收购代码托管平台GitHub。

安装

https://git-scm.com/downloads

下载对应操作系统的Git客户端版本

Linux

从RHEL上安装非常简单

yum install git

windows

下载对应的32位或者64版本,点击安装即可

git --version 查看版本号

概念

img_20250926_155853.png
名称  
Repository 仓库、版本库 git初始化后,会在当前目录生成一个 .git 目录,这就是版本库
Workspace工作空间、工作区 .git 文件所在的目录就是工作区,一般是项目的根目录
index索引 介于工作区和版本库之间,暂存修改的
remote 远程版本库 网络上的另一个版本库,可以和本地库交互

使用

初始化一个版本库

mkdir test 
cd test
# 初始化库
git init

└─$ ls .git                              
config  description  HEAD  hooks  info  objects  refs
  • 在当前目录中增加了一个.git目录,不要自行修改这个目录里面的文件
  • 当前目录一般是项目的根目录

添加文件

创建一个html文件

echo 'line 1' > readme
echo '<html><head><title>test</title></head><body>My Website</body></html>' > index.html

查看状态 git status

└─$ git status 
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html
        readme

nothing added to commit but untracked files present (use "git add" to track)

└─$ git status -s
?? index.html
?? readme

-s, -short短格式输出

可看到当前有一个刚创建的文件为红色,需将跟踪文件使用 add 命令添加到暂存区 index ,给git管理

添加 add

1、单个文件添加

# 1加入管理 2 记录变化 3 只是进入到暂存区,不算提交
git add <filename>

这一步是把文件的当前变化添加到索引中,也就是以后这个文件需要版本库来跟踪管理,注意这不是提交。

此时,文件还可以继续修改,还可以添加新的被跟踪文件,一定要add才能把这些改变加入到索引中

└─$ git add  readme
└─$ git status     
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   readme

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html

2、批量添加

git add .
#.点号,代表当前目录,这条命令将递归添加当前目录及其子目录所有文件
#只要是目录,就会递归添加改目录下的文件和子目录

└─$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.html
        new file:   readme

Git的文件分类

  • 追踪的Tracked,已经加入版本库的文件
  • 未追踪的Untracked,未加入到版本库的未被管理的文件
  • 忽略的Ignored,git不再关注的文件,例如一些临时文件

.gitignore=文件中,目录以/结尾,行起始的!的是取反

.gitignore内容如下

*.ipynb
__pycache__/
.python-version

忽略文件不需要自己写,Python的已经有写好 https://github.com/github/gitignore/blob/master/Python.gitignore

其他语言的在这里找 https://github.com/github/gitignore

wget -O .gitignore https://github.com/github/gitignore/blob/main/Python.gitignore

提交代码 git commit

└─$ git commit
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "[email protected]"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'jasper@kali.(none)')
配置本地用户名和邮箱

这是个好习惯,建议这时候一定要加上

git config --global user.name "my"
git config --global user.email "[email protected]"

# 这些内容对应~/.gitconfig文件,是 用户级别 的配置文件
$ cat ~/.gitconfig
[user]
    name = my
    email = [email protected]

# 命令显示
git config --list
git config --global user.name
git config --global user.email
#1命令行方式提交
git commit -m "firstcommit"

#2可视化界面提交
git commit filename
#操作如同Linux,i=输出,wq为保存退出
#在红色区域输出提交时的说明,需描述本次提交改动了什么文件,什么内容。

commit 命令:提交更改到版本库

  • -m:填写本次日志消息,必须写。工作中,程序应该对每一次提交写明做了什么改动。

修改后再次提交

sed -i -r 's@(<body>)(.*)(</body>)@\1Welcome to \2\3@' index.html

└─$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

#再提交
└─$ git commit -m "Second Commit"

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

看上面的信息,commit之后发现,变动的文件index.htm并没有提交

git add index.html

#再提交,提交成功
└─$ git commit -m "Second Commit"

[master 946c993] Second Commit
 1 file changed, 1 insertion(+), 1 deletion(-)

文件的生命周期

img_20250926_172021.png
  • 文件add后,就成为可跟踪文件的未修改状态unmodified,修改后,文件就变成modified状态。
  • 再次add后,将变化提交到索引,状态变为staged,这才能提交。提交成功,文件状态从staged变回unmodified。

git的提交

git的提交分为两个步骤:

  1. 暂存变更:add作用是把新文件或者文件新的改动添加到一个暂存区stage,也就是加入到index中
  2. 提交变更:commit提交的是暂存区中的改动,而不是物理文件目前的改动,提交到当前分支,默认是master分支

也可以使用下面命令,将两步合成一步

git commit readme

如果改动了一批文件,一个个写名字很麻烦,使用下面的命令

git commit -a
  • -a,–all 会把所有跟踪的文件的改动自动暂存,然后commit。上面命令未提交message,会出现一个类似vi命令的操作界面,需要编写message之后,才行。

也可以使用下面的命令,把message信息一并填写了。

git commit -a -m "message"

增补

第二次提交后,忘记修改文件内容或者忘记增加文件,又不想增加提交记录。

touch about.htm
git add about.htm

#重新生成提交记录,替换当前分支最近的提交
git commit -a --amend -m 'again commit'
  • –amend 修改,通过创建一个新的commit来replace当前分支的顶部。也可以在命令中继续使用-m选项直接提交message。

git log 查看一下版本库里面提交的历史记录

diff 比较

  • git diff 查看被跟踪文件未暂存的修改,比较暂存区和工作区
  • git diff --cached 查看被跟踪文件暂存的修改,比较暂存区和上一次commit的差异
  • git diff HEAD 查看被跟踪文件,比较工作区和上一次commit的差异。HEAD指代最后一次commit
echo "line 2" >> readme

# modified状态
└─$ git diff   # 比较暂存区和工作区
diff --git a/readme b/readme
index 89b24ec..7bba8c8 100644
--- a/readme
+++ b/readme
@@ -1 +1,2 @@
 line 1
+line 2

└─$ git diff --cached #比较暂存区和上一次commit的差异

└─$ git diff HEAD # 比较工作区和上一次commit的差异 
diff --git a/readme b/readme
index 89b24ec..7bba8c8 100644
--- a/readme
+++ b/readme
@@ -1 +1,2 @@
 line 1
+line 2

HEAD

  • HEAD可以看做是一个游标,一般是指向当前分支最后一次提交。
  • HEAD的值存储在.git/HEAD中。
  • HEAD ,指代最后一次commit
  • HEAD^ ,指代上一次提交
  • HEAD^^ ,指代上上一次提交
  • 上n次提交,表示为 HEAD~n
└─$ git diff HEAD^ readme 
diff --git a/readme b/readme
index 89b24ec..7bba8c8 100644
--- a/readme
+++ b/readme
@@ -1 +1,2 @@
 line 1
+line 2

检出

checkout 用于(创建)切换分支,或恢复工作区文件。

注意:checkout会重写工作区,这个命令还是较为危险的

命令 说明
git checkout 列出暂存区可以被检出的文件
git checkout file 从暂存区检出文件到工作区,就是覆盖工作区文件,可指定检出的文件。但是不清除stage
git checkout commit file 检出某个commit的指定文件到暂存区和工作区
git checkout . 取出暂存区的所有文件到工作区
#不小心写错了,工作区内容覆盖了
echo > readme # 清除工作区文件内容
git checkout readme # 从暂存区检出到工作区,工作区文件有了内容
git checkout HEAD readme # 使用当前分支的最后一次commit检出覆盖暂存区和工作区
# 下面3条命令结果一致了
$ git diff
$ git diff --cached
$ git diff HEAD
命令 说明
git reset 列出将被reset的文件
git reset file 重置文件的暂存区,和上一次commit一致,工作区不影响
git reset --hard 重置暂存区与工作区,与上一次commit保持一致
echo "<html>Welcome about</html>" > index.html
git add index.html # 添加到暂存区
git reset index.html # 使用最后一次提交覆盖暂存区
cat index.html # 工作区文件有内容

git add index.html # 添加到暂存区
git reset --hard # 重置暂存区与工作区为上一次commit
cat index.html # 工作区文件
命令 说明
git reflog 显示commit的信息,只要HEAD发生变化,就可以在这里看到
git reset --soft commit 重置当前分支的HEAD为指定commit,但暂存区区和工作区不变
git reset commit 重置当前分支的HEAD为指定commit,同时重置暂存区,但工作区不变
git reset --hard [commit] 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
git reset --keep [commit] 重置当前HEAD为指定commit,但保持暂存区和工作区不变
#创建一个新文件
└─$ echo 'print("HelloWorld!")' > app.py                                                    
└─$ git add .         
└─$ git commit -m "commit add app.py"      
[master 1e2131d] commit add app.py
 1 file changed, 1 insertion(+)
 create mode 100644 app.py

 # 重置暂存区和工作区,与指定commmit一致
└─$ git reset --hard 946c9936f
HEAD is now at 946c993 Second Commit
└─$ ll
total 8
-rw-rw-r-- 1 jasper jasper 80 Sep 26 17:44 index.html
-rw-rw-r-- 1 jasper jasper  7 Sep 26 17:50 readme

└─$ git reflog   # 查看log         
946c993 (HEAD -> master) HEAD@{0}: reset: moving to 946c9936f
1e2131d HEAD@{1}: commit: commit add app.py
7845649 HEAD@{2}: reset: moving to HEAD
7845649 HEAD@{3}: reset: moving to HEAD
7845649 HEAD@{4}: commit (amend): 2 append 2.1
767e203 HEAD@{5}: commit: add gitignore
946c993 (HEAD -> master) HEAD@{6}: commit: Second Commit
cf4ad40 HEAD@{7}: commit (initial): create files

# 指定到之前的提交
└─$ git reset --hard 1e2131d  
HEAD is now at 1e2131d commit add app.py
└─$ ll
total 12
-rw-rw-r-- 1 jasper jasper 21 Sep 26 17:53 app.py
-rw-rw-r-- 1 jasper jasper 80 Sep 26 17:44 index.html
-rw-rw-r-- 1 jasper jasper 16 Sep 26 17:53 readme
└─$ git reflog              
1e2131d (HEAD -> master) HEAD@{0}: reset: moving to 1e2131d
946c993 HEAD@{1}: reset: moving to 946c9936f
1e2131d (HEAD -> master) HEAD@{2}: commit: commit add app.py
7845649 HEAD@{3}: reset: moving to HEAD
7845649 HEAD@{4}: reset: moving to HEAD
7845649 HEAD@{5}: commit (amend): 2 append 2.1
767e203 HEAD@{6}: commit: add gitignore
946c993 HEAD@{7}: commit: Second Commit
cf4ad40 HEAD@{8}: commit (initial): create files

reset操作,要慎重

撤销

git revert

#修改并提交,发现错误,想要倒回去一个版本
echo 'line 4' > readme              
git commit -a -m 'commit add line 4'

#撤销最后一次提交,生成新的提交
git revert HEAD

└─$ git log        
commit 1abde1cd208d9e9531efb69228ea2820421d52ad (HEAD -> master)
Author: my <[email protected]>
Date:   Fri Sep 26 17:58:04 2025 +0800

    Revert "commit add line 4"

    This reverts commit 4999fac66d5ba6090ed5db471be66cfdf1c6a64e.

commit 4999fac66d5ba6090ed5db471be66cfdf1c6a64e
Author: my <[email protected]>
Date:   Fri Sep 26 17:56:20 2025 +0800

    commit add line 4
└─$ git reflog     
1abde1c (HEAD -> master) HEAD@{0}: revert: Revert "commit add line 4"
4999fac HEAD@{1}: commit: commit add line 4
1e2131d HEAD@{2}: reset: moving to 1e2131d
946c993 HEAD@{3}: reset: moving to 946c9936f
1e2131d HEAD@{4}: commit: commit add app.py
7845649 HEAD@{5}: reset: moving to HEAD
7845649 HEAD@{6}: reset: moving to HEAD
7845649 HEAD@{7}: commit (amend): 2 append 2.1
767e203 HEAD@{8}: commit: add gitignore
946c993 HEAD@{9}: commit: Second Commit
cf4ad40 HEAD@{10}: commit (initial): create file
  • revert主要用在主分支上,虽然撤销了提交的修改,但log中保留了信息。在工作分支上,可以采用reset。
  • revert只是撤销了指定commit的修改,会继续保留其他的修改,会在当前分支后生成一个新的commit。
  • reset会把回到的commit之后的commit删掉了。

移动和删除

  • git mv src dest 改名,直接把改名的改动放入暂存区
  • git rm file 会同时在版本库和工作目录中删除文件,真删除
  • git rm --cached file 将文件从暂存转成未暂存,从版本库中删除,但不删除工作目录的该文件,即文件恢复成不追踪的状态

以上都算是改动,必须commit才算真改动

echo "test" > test.py

git add test.py
git commit -m "mv and delete"

# 改名
git mv test.py t.py
└─$ git status         
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    test.py -> t.py

git commit -m "mv test.py -> t.py"

└─$ ll
total 16
-rw-rw-r-- 1 jasper jasper 21 Sep 26 17:53 app.py
-rw-rw-r-- 1 jasper jasper 80 Sep 26 17:44 index.html
-rw-rw-r-- 1 jasper jasper 16 Sep 26 17:58 readme
-rw-rw-r-- 1 jasper jasper  5 Sep 26 18:06 t.py

# 删除 git rm
└─$ git rm t.py
rm 't.py'
└─$ ll
total 12
-rw-rw-r-- 1 jasper jasper 21 Sep 26 17:53 app.py
-rw-rw-r-- 1 jasper jasper 80 Sep 26 17:44 index.html
-rw-rw-r-- 1 jasper jasper 16 Sep 26 17:58 readme
└─$ git status 
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    t.py
└─$ git commit -m "del t.py"          
[master a9489b6] del t.py
 1 file changed, 1 deletion(-)
 delete mode 100644 t.py

push到服务器

本地搭建了一个github私服,模拟GitHub http://192.168.112.135:3000/my/test.git

  • 关联远程版本库
    git remote 列出所有远程仓库
    git remote -v 详细列出所有远程仓库
    git remote add [shortname] [url] 指定一个名称指向远程仓库
$ git remote add origin http://[email protected]:3000/my/test.git
$ cat .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = http://[email protected]:3000/my/test.git
    fetch = +refs/heads/*:refs/remotes/origin/*

远程版本库名origin,这是个习惯用法,将建立origin和后面url的映射,这些信息保存在.git/config文件的新的段[remote“origin”] 中

注意: http://[email protected]:3000/my/test.git 加上用户名,否则push会报401

  • git config --system 在/etc/gitconfig 文件中读写配置
  • git config --global 在 ~/.gitconfig 文件中读写配置
  • .git/config 这个文件是 版本库级别 设置文件,这里的设置具有最高优先级

推送数据

$ git push -u origin master 
Password: 
Counting objects: 7, done. 
Delta compression using up to 2 threads. 
Compressing objects: 100% (5/5), done. 
Writing objects: 100% (7/7), 583 bytes, done. 
Total 7 (delta 0), reused 0 (delta 0) 
To http://[email protected]:3000/my/test.git 
* [new branch]      master -> master 
* Branch master set up to track remote branch master from origin.
AI生成项目python运行12345678910

输入密码就可以连接到远程仓库了。

私有的仓库,必须登录,只能用户自己看,为了方便,修改为公有的。

git push <远程主机名> <本地分支名>:<远程分支名>
$ git push origin master   # 指定推送到的远程主机和分支
$ git push origin           # 指定当前分支推送到的主机和对应分支 
$ git push -u origin master # 指定远程默认主机和分支 
$ git push                  # simple方式,默认只推送当前分支到默认关联的远程仓库
  • -u 第一次远程推送的时候加上,以后就可以不使用-u参数,可以git push origin master,也可以git push都使用默认。
echo "welcome about" > about.htm 

git commit -a -m "修改了about.htm" 
git push origin master # 或者git push

从远程库克隆

  • 这一次使用git协议连接远程库。
  • 为了演示跨平台,这里使用windows系统。
  • 建议使用Git的windows客户端的 git bash ,它含有常用ssh命令
  • 配置本地用户名、邮箱
$ git config --global user.name "jack" 
$ git config --global user.email "[email protected]" 
$ cat ~/.gitconfig 
[user]    
    name = jack    
    email = [email protected]
  • 删除windows当前用户=.ssh=文件夹
  • $ ssh-keygen -t rsa -C "[email protected]"
    • -t 加密算法类型
    • -C comment 描述信息
$ ssh-keygen -t rsa -C "[email protected]"
Generating public/private rsa key pair. 
Enter file in which to save the key (/c/Users/Administrator/.ssh/id_rsa): # 直接回车 
Enter passphrase (empty for no passphrase): # 直接回车 
Enter same passphrase again: # 直接回车 
Your identification has been saved in /c/Users/Administrator/.ssh/id_rsa. # 私钥
Your public key has been saved in /c/Users/Administrator/.ssh/id_rsa.pub. # 公钥 
The key fingerprint is:
SHA256:ZxALWxgiq1UUw6TpS+p/hBeTeYOmAbIRVQNUZZ0fUxs [email protected] 
The key's randomart image is: 
+---[RSA 2048]----+ 0
|.+=B@o=+o. .E    | 
|o. *.=.+ooo  o   | 
|.o*   = o. o.    | 
|.+ . B o ..      | 
|. o = + S o      | 
| o + o   o       | 
|. . o            | 
|.    .           | 
| ....            | 
+----[SHA256]-----+

$ cd $ ls .ssh id_rsa  id_rsa.pub

$ pwd 
/c/Users/Administrator 
  • 打开gogs的用户设置 -> ssh密钥
  • 打开公钥文件 -/.ssh/id_rsa.pub ,将内容贴入“密钥内容”框中,点击“增加密钥”,密钥名称自己填写
  • 那么SSH登录的用户使用的链接如下图
  • SSH链接远程库
    在windows上找一个空目录,执行下面的克隆命令
    注意,第一次使用ssh连接有提示,敲入yes
$ git clone [email protected]:my/test.git 
Cloning into 'test'... 
remote: Counting objects: 28, done. 
remote: Compressing objects: 100% (20/20), done. 
remote: Total 28 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (28/28), done.

克隆成功

下面就可以使用这个初始的项目文件开发了

Git项目开发和多人协作

Pycharm中使用git

创建远程版本库

git私服创建cmdb项目版本库

  • 提前添加密钥到git私服
  • 获得远程仓库地址,如 [email protected]:my/cmdb.git
  • 克隆代码到本地
    • 打开IDE工具Pycharm
      • 从版本控制工具中获取项目,选择Git
        • 菜单中选择Project from Version Control–>Git
      • 选择项目目录,填入远程版本库地址
      • Clone成功,并直接用Pycharm打开项目。
#查看远程信息
jasper@jasper MINGW64 /d/project/PythonProject/cmdb (master)
$ git remote
origin

jasper@jasper MINGW64 /d/project/PythonProject/cmdb (master)
$ git remote -v
origin  [email protected]:my/cmdb.git (fetch)
origin  [email protected]:my/cmdb.git (push)

项目开发

  • 添加app.py文件
    • 提示是否加入到git

编写源码 app.py

if __name__ = "__main__":
        print("helle world")

第一次提交

  • Git–>Commit
  • 这里可以选择提交,或提交并推送。本次选择提交。 并写上提交信息。

Pycharm中查看版本信息

  • 菜单栏–>View–>Tool Window –>Git(Altr+9)

这只是放入到本地仓库。

推送

  • Git–>Push
  • 成功push。私服查看

分支branch

多人协作一起开发,开发项目中不同的独立的功能,这些功能可能需要好几天才能完成。又或者为客户定制软件,往往需要一个不同的定制需要。这往往需要在代码上开辟不同的分支。

代码中至少有一个分支,就是主干分支或者称主分支master,默认都是在主分支上开发。

分支名

分支名

  • 分支名在版本库中必须唯一
  • 不能以 - 开头
  • 可以使用 /,但是不能以它结尾,被它分割的名称不能以.开头
  • 不能使用两个连续的 ..
  • 不能包含任何空白字符、Git的特殊符号

注: 分支名一般要么叫 Master 要么叫 dev

单分支

master .---> . ---> .

#点表示每一次提交commit

项目往往是并行多人开发的,都在主分支上克隆,然后修改提交,那么主分支就会有存在大量的冲突。甚至有一些 不完善代码提交,主分支就混乱不堪,不可维护了。

再一个,如果一次提交后,需要发布一个版本,这个版本以后需要独立维护、开发,而主分支还需要继续发展,怎 么办?例如3.5版本发布后,增加了新功能3.6,然后3.5版本还需要修改bug。

需要使用多分支。

多分支

创建分支

需要指明从什么分支上创建什么名字的分支。

可以在版本控制的Log标签页查看(Pycharm Alt+9)。

  • New branch –> dev

成功创建分支。相当于 git checkout -b dev

创建一个工具模块,并提供一个封装函数。

# utils/__init__.py
from urllib import request

class Request(request.Request):
    def __init__(self, url):
        super().__init__(url)
        self.add_header(
            'User-agent',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36'
        )

    def get(self):
        """返回结果"""
        return request.urlopen(self)

Git –> Push commit 并抢着到远程仓库。

协作开发

打开Linux桌面系统。

git config --global user.name 'ubuntu'
git config --global user.email '[email protected]'

└─# cat ~/.gitconfig                                                   
[user]
        name = ubuntu
        email = [email protected]

# ssh 密钥
ssh-keygen -t rsa -C '[email protected]'
cat .ssh/id_rsa.pub

同样操作,clone项目,然后checkout到dev分支

git clone [email protected]:my/cmdb.git
cd cmdb
git checkout dev

mkdir monitor
└─# vim monitor/__init__.py
from utils import Request

def ip_check(url):
    #'http://myip.ipip.net'
    request = Request(url)
    pass

存储stash

命令 说明
git stash 暂时存储最后一次提交后的变化,放入栈中
git stash pop 从栈中取出刚才保存的变化,并合并

ubuntu正在开发过程中,突然领导说app.py中有一个紧急修改bug,需要马上修复。可是现在代码没有写完,不想提交。

git add monitor/

└─# git stash       
Saved working directory and index state WIP on dev: 60d43e5 2 增加utils和Request封装类
└─# ll
total 8
-rw-r--r-- 1 root root   52 Sep 27 14:34 app.py
drwxr-xr-x 2 root root 4096 Sep 27 14:38 utils

这时候发现app.py急需完善代码,但是分发器模块块没有完成不想提交,这时候就需要stash了。

如果是Pycharm, Git–>Stash Changes–>Create Stash

执行完,工作区回到了上次提交的样子,回到app.py中完成修改,最后提交。

└─# vim app.py
if __name__ == '__main__':
    print('hello world!!!!')


#提交并推送
git add app.py  
git commit -m 'fix app.py'
git push 

现在可以unstash并pop 刚才保存的代码,并开发。

└─# git stash list  
stash@{0}: WIP on dev: 60d43e5 2 增加utils和Request封装类

└─# git stash show
 monitor/__init__.py | 5 +++++
 1 file changed, 5 insertions(+)

└─# git stash pop   
On branch dev
Your branch is up to date with 'origin/dev'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   monitor/__init__.py

Dropped refs/stash@{0} (69e3b225c153c487509a24c23ed909ca36561cdb)

└─# ll
total 12
-rw-r--r-- 1 root root   57 Sep 27 14:49 app.py
drwxr-xr-x 2 root root 4096 Sep 27 14:54 monitor
drwxr-xr-x 2 root root 4096 Sep 27 14:38 utils

如果是Pycharm, Git–>UnStash Changes

  • Stashes
  • Pop Stash –> Pop Stash

monitor/__init__.py文件又变成了刚才修改过的样子,继续完成代码,提交。

└─# vim monitor/__init__.py
from utils import Request

def ip_check():
    request = Request('http://myip.ipip.net')
    with request.get_text() as response:
        print(response)

└─# git add monitor/
└─# git commit -m 'add monitor/__init__.py'
└─# git push   

应用场景

  • 开发中,当前手中的工作没有完成,需要 中断 当前工作来完成其他请求,例如修复Bug。
  • 已完成的工作内容提交不合适,可能还要需要大的调整,但是紧急请求又不能不做,就需要stash存储未完成的工作(上次提交后做的修改)。

分支branch

注:以下的操作都在Pycharm中完成,其它IDE都可以实现类似的功能

  • 多人协作一起开发,开发项目中不同的独立的功能,这些功能可能需要好几天才能完成, 又或者定制版本,往往需要一个不同的定制需求。
  • 代码中至少有一个分支,就是主干分支或称主分支Master,默认都是在主分支上开发。

Pull

如果要对某个分支代码进行开发,应该先对该分支进行pull操作,以拿回新代码。

如windows下用户开始pull dev代码。

if __name__ == '__main__':
    print('hello world')

    print('=' * 30)

$ git status
On branch dev
Your branch is up to date with 'origin/dev'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   app.py
git pull origin dev

发现冲突

15:14:03.612: [cmdb] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false pull --no-stat -v --progress origin dev
remote: Total 12 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)        
From 10.0.0.152:my/cmdb
 * branch            dev        -> FETCH_HEAD
   60d43e5..21c6a1e  dev        -> origin/dev
error: Your local changes to the following files would be overwritten by merge:
        app.py
Please commit your changes or stash them before you merge.
Aborting

冲突解决

由于某种原因,ubuntu对app.py进行了修改并push了代码。

之后windows用户并没有pull操作,直接对app.py进行了修改。

测试成功。先commit.

然后再PUSH代码。

有冲突产生,需要后提交者解决冲突,点击Merge.

合并代码后,点击Apply. 然后PUSH到远程仓库

合并merge

dev开发告一段落,需要将功能合并入master。 切换回到master,检出master

git checkout master
git merge --no-ff dev

开始合并,选择No Fast Forword合并

CVS–>Git–>MergeChanges

  • dev No fast forward
  • Merge

目前的合并,只是本地,需要push到远程库

当然还可以继续检出dev分支,继续开发,开发好了,合并进来

Fast Forward 合并

img_20250927_172851.png

从前面操作的图中可以看到,默认NoFF不勾选,也就是默认使用FF方式合并。

no-ff的好处是,可以看清楚开发分支上的代码改动。

上面dev分支总是开发中的代码,dev测试、审查后合并到master中。

master分支都是稳定的代码,可以发布部署。

Tag

git tag <标签名>  #打标签
git tag -l  #查看

git push --progress --porcelain origin refs/heads/master:master --follow-tags
  • Git–>New Tag
  • Git–>Push 勾选Push Tags Curren Branch

GitFlow工作流

不同公司,不同的项目规模,不同的管理水平都有着不同Git工作流方式。

最佳实践

  • 使用Git一般至少2个分支:master和develop
    • master,主干,生产环境都来主干分支上拿数据部署,也可以使用钩子自动完成
    • develop,开发分支,开发人员都是检出这个分支开发
    • 辅助分支
      • feature 分支,具体的功能开发分支,只与 develop 分支交互。
      • release 分支,发布版本
      • hotfix 分支,紧急bug修复的版本,最后需要合并到develop 和 master中。
img_20250927_175044.png
emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike