Python 全栈系列54 - git的版本分支控制

说明

建立了自有算网之后,在各主机间搬运文件会有一定的麻烦,因此使用自建的git服务来完成这一管理。另外,git提供的版本控制将用于实践:

  • 1 AB test : git clone两份项目文件就了,然后分别切换到要比较的分支启动(最好是B Server的方式启动,避免端口的管理,因此在不同版本的B Server 需要“表名自己的身份”,也就是结果中要附带版本号)
  • 2 项目的扩展与按需交付。想象一个场景,先建立一个具有A,B,C功能的V1版,后来又慢慢添了D、E、F功能,D依赖于B, E依赖于C, F不依赖。那么用户可以通过自己的需求拉取指定的版本,从而实现付费-功能-开发间的隔离与控制。

1 环境

使用m1主机搭建git服务。还是专门建一个git用户,避免项目中的一些东西干扰到系统。由于m1经过frp透传,所以git本质上操作的是一个端口非默认的主机。

命令格式如下

git clone ssh://git@111.222.333.444:1234/home/git/YOURPROJECT.git 

创建用户和安装过程setup_git.sh

#!/bin/bash

# 除了输入密码和确认密码,一律回车吧
adduser git

# 如果新建错了可以使用下面的指令进行删除用户
# $ userdel git

# 创建文件夹
mkdir /opt/git
# 切换过去
cd /opt/git

apt install git

# 查看版本,以确认成功(git version 2.7.4)
git --version

# 修改文件夹可写权限(毕竟git就是频繁读写)
chmod -Rf 777 /opt/git

# 修改权限
echo "git ALL=(ALL) NOPASSWD:ALL ">> /etc/sudoers


# 切换到git用户
su git 

# 切换到用户目录(/home/git)
cd ~ && mkdir .ssh && cd .ssh 

# 这步可以导入现有公钥,也可以不导。因为现有的公钥主要是用于做ssh连接, 还是要生成一对git专用的,这样其他主机才能用私钥访问
# echo "你的公钥" >authorized_keys
touch authorized_keys

# 这句我不知道要不要加,之前没登上是我命令看错了(把git下的授权公钥放到sshd中)
# 这句话不要加,加了root就没法ssh(但是git用户可以)
# echo "AuthorizedKeysFile /home/git/.ssh/authorized_keys">>/etc/ssh/sshd_config
# 如果加了,大概率要重启一下sshd
systemctl restart sshd.service

接下来创建一个项目。例如项目可以以prj1, prj2…的方式命名setup_new_gitwarehouse.sh

su git 

cd ~ 

## 建立一个叫codes的仓库并初始化
mkdir ~/codes.git && git init --bare codes.git && chown -R git YOURPROJECT.git 

有可能git还需要执行用户的初始化命令才能使用,应该是可以做到给每个项目配不同的用户

# git要求创建用户
git config --global user.name "username"
git config --global user.email "user@email.com"

如果之前上传了m0的公钥,此时已经可以执行命令拉取项目了。

git clone ssh://git@111.222.333.444:1234/home/git/YOURPROJECT.git 

算网内其他主机

为了做到其他主机可以直接访问git, 要生成一对秘钥。我在m1的root下执行

ssh-keygen -t rsa -C "user@email.com"
# 会生成一对秘钥放在
/root/.ssh/id_rsa
/root/.ssh/id_rsa.pub

其中id_rsa.pub是公钥,要直接写入git下面的authorized_keys

echo "ssh-rsa 公钥内容 user@email.com" >>/home/git/.ssh/authorized_keys

现在假设算网内的m4需要进行git同步,那么将id_rsa文件拷贝/重名为id_rsa_git,假设放在用户家目录的.ssh之下

# 首先将rsa文件改为只读

chmod 600 ~/.ssh/some_rsa

# 增加id
ssh-add ~/.ssh/some_rsa


# 如果不可以,执行
ssh-agent bash


# 检查是否已经装好
ssh-add -l


# 对于git, 如果拉取远端的prjxxx.git ,那么通常
cd /opt && git clone ssh://git@111.222.333.444:1234/home/git/prjxxx.git

这样环境设置就可以了,可以开始研究git 分支和版本的控制。

2 版本和分支

Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照

这部分的参考来自这篇文章

git的提交会发生什么

当使用 git commit 进行提交操作时,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和, 然后在 Git 仓库中这些校验和保存为树对象。随后,Git 便会创建一个提交对象, 它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。 如此一来,Git 就可以在需要的时候重现此次保存的快照。

在这里插入图片描述

Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。

整体流程大致是这样的:
在这里插入图片描述
git的核心其实是树,分支的前进和后退完全可以通过遍历(特定的路径)和回溯复现。

Git 的 master 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它。

2. 分支创建

git branch  NewBranch

对于刚拉取的空项目,如果尝试创建新的分支会报错
fatal: Not a valid object name: 'master'.
原因是没有提交一个对象,要先commit之后才会真正建立master分支,此时才可以建立其它分支
所以先做一个简单提交。

touch 说明.md
git add 说明.md
git commit -m 'Intial Project'
---
[master (root-commit) 8b19119] Intial Project
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 "\350\257\264\346\230\216.md"

此时执行

git branch  NewBranch
git status
---
On branch master
Your branch is based on 'origin/master', but the upstream is gone.
  (use "git branch --unset-upstream" to fixup)

nothing to commit, working tree clean
---
在本例中,你仍然在 master 分支上。 因为 git branch 命令仅仅 创建 一个新分支,并不会自动切换到新分支中去。

当我执行推送之后

git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 216 bytes | 216.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://111.229.116.147:6000/home/git/codes.git
 * [new branch]      master -> master

---再执行
git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
关于commit和push

此处参考这篇文章
git作为支持分布式版本管理的工具,它管理的库(repository)分为本地库、远程库。

git commit操作的是本地库,git push操作的是远程库。

git commit是将本地修改过的文件提交到本地库中。
git push是将本地库中的最新信息发送给远程库。

那有人就会问,为什么要分本地commit和服务器的push呢?

因为如果本地不commit的话,修改的纪录可能会丢失。
而有些修改当前是不需要同步至服务器的,所以什么时候同步过去由用户自己选择。什么时候需要同步再push到服务器。

分支的确定

Git 又是怎么知道当前在哪一个分支上呢? 也很简单,它有一个名为 HEAD 的特殊指针。 请注意它和许多其它版本控制系统(如 Subversion 或 CVS)里的 HEAD 概念完全不同。 在 Git 中,它是一个指针,指向当前所在的本地分支(译注:将 HEAD 想象为当前分支的别名)。

查看当前所指的分支

git log --oneline --decorate
---
8b19119 (HEAD -> master, origin/master, NewBranch) Intial Project

注:在英文状态下按q才会退出屏幕

3 分支切换

git checkout NewBranch

在这里插入图片描述
用另一个命令查看分支。当前指向NewBranch, 看出来 origin/master是远程分支

git branch -a

* NewBranch
  master
  remotes/origin/master

在新分支上做一个改变

echo 'aa' >> 说明.md
$ git add .
$ git commit -m 'modify 1'
[NewBranch 3ae58cb] modify 1
 1 file changed, 1 insertion(+)
 
$ git status
On branch NewBranch
nothing to commit, working tree clean


 $ git push
fatal: The current branch NewBranch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin NewBranch

在远端没有分支,所以无法创建
git push --set-upstream origin NewBranch
Counting objects: 3, done.
Writing objects: 100% (3/3), 240 bytes | 240.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://IP:port/home/git/codes.git
 * [new branch]      NewBranch -> NewBranch
Branch 'NewBranch' set up to track remote branch 'NewBranch' from 'origin'
分支的差异

我们刚才做的事:先建立了一个空文件说明.md,然后提交master分支并同步远程master(origin master)。然后建立新分支NewBranch, 然后向说明.md追加了“aa”。

$ NewBranch  cat 说明.md
aa
$ NewBranch  git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ master cat 说明.md
--没有数据--

所以在不同分支下的改动是互不干扰的。换句话说,如果想实现AB Test的化按分支来就可以了。(启动的时候同步不同分支然后启动)

追溯分支的改变(commit)

首先切换到要观察的分支,然后执行命令git log --oneline, 可以看出来,的确是每个时刻存了一个快照,前面的7位16进制数就是快照简称。

在这里插入图片描述

–oneline: 将commit显示成一行
–no-decorate: 将tag和head名隐藏掉

如果要看HEAD指针的指向,可以执行cat .git/HEAD。比较一下master分支的指针:
在这里插入图片描述

再回到NewBranch之下,增加一个new2.md的新文件,这样我们在NewBranch上就有两次提交了。
在这里插入图片描述
假设我们反悔,即modify这步产生了很多乱七八糟的变更(想象在50个文件里改了500行代码),我们要回退。

git reset --hard  3ae58cb

在这里插入图片描述
此时再看文件,new2.md已经不见了。
在这里插入图片描述
分支日志 git log --oneline
在这里插入图片描述
本地回退以后,远端呢?
在这里插入图片描述
执行远程回退,本部分参考这篇文章

git push origin HEAD --force
Total 0 (delta 0), reused 0 (delta 0)
To ssh://111.222.333.444:1234/home/git/codes.git
 + 5a20bb4...3ae58cb HEAD -> NewBranch (forced update)

再使用git status查看时发现已经好了。
在这里插入图片描述

再次反悔

如果我们又反悔了,发现modify2挺好的想要再改回来(像不像甲方爸爸的需求?)。先查看所有分支变化的记录

git log --oneline --decorate --graph --all

在这里插入图片描述
可以看到文件又回来了
在这里插入图片描述
此时还要同步一次远端
在这里插入图片描述
可以再查看一下日志git log --oneline,可以看到又恢复了第一次提交modify2时的样子
在这里插入图片描述
到这里基本已经实现了目的。对于大型的项目,如果能做好commit标签的标注,那么是可以灵活进行切换的。不过要用的好,我觉得还是需要借助外部的图库来辅助,靠人是没法记住那么多分枝变化的。

3 和docker-compose 项目的配合

为每个docker-compose项目都独立设立一个文件夹进行同步,主要由m0发起变化,然后各算网主机拉取。
里面有一个地方需要注意:如果项目产生了本地的文件(例如1000个文件)怎么办?
这里做个自我约定,git项目只同步通用的文件,每个项目产生的新文件不同步。每个项目通过.gitignore文件指定不同步的文件夹。这里约定data和log不同步,因此项目里如果要产生具体的实例文件,就放在data和log两个文件夹下面。如果项目有额外的特例,那么就单独的在文件里声明不同步。这些文件最好都加一个git_local的前缀,方便识别。
在这里插入图片描述
通用的.gitignore内容,具体的过滤规则可以参考这篇文章

/rabbit/data/
/rabbit/log/

测试一下:
远端建立新的项目setup_new_gitwarehouse.sh, 登录root用户

su git 

cd ~ 

mkdir ~/prj12.git && git init --bare prj12.git && chown -R git prj12.git 

在本地找一个文件夹GitPath, 然后clone

git clone ssh://git@111.222.333.444:1234/home/git/prj12.git 

将项目文件循环拷贝至clone下来的空文件夹

cp -r OriginalPath/prj12/ GitPath/prj12/

在这里插入图片描述
data和log文件夹没有上传,ok。

Note: git不会自动同步空文件夹,大部分时候不是事。就记得如果要访问文件夹先判一下。(我的dm里面有这样的函数,不麻烦)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值