一、Git是什么

Git是一个免费开源的分布式版本控制系统,有Linux Torvaldds为帮助管理Linux内核开发。

二、Git与SVN、CVS的区别

  • SVN/CVS,集中式存储,有中央服务器,必须联网才能使用,如果中央服务器瘫痪,任何人都应用不了(基于文件差异的版本控制)
20220704204455-2022-07-04-20-44-55
  • Git 分布式存储,没有中央服务器,每个人的副本的都是完整的。(版本文件快照)
20220704204517-2022-07-04-20-45-17

三、Git的工作流程

20220704204557-2022-07-04-20-45-57
  • workspace:工作区
  • Index/Stage:暂存区(一般在.git目录下的index中 )
  • Repository:版本库(.git
  • Remote:远程版本库

四、Git的安装

安装

$ sudo apt install git

配置(全局)

$ git config --global user.name "Youre Name"
$ git config --global user.email "email@example.com"

查看配置

$ git config --list

五、Git的使用

  1. 新建目录,初始化为git仓库(repository)
$ mkdir git_learn
$ git init

初始化后的内容如下

.
└── .git
    ├── branches
    ├── config
    ├── description
    ├── HEAD
    ├── hooks
    │   ├── applypatch-msg.sample
    │   ├── commit-msg.sample
    │   ├── fsmonitor-watchman.sample
    │   ├── post-update.sample
    │   ├── pre-applypatch.sample
    │   ├── pre-commit.sample
    │   ├── prepare-commit-msg.sample
    │   ├── pre-push.sample
    │   ├── pre-rebase.sample
    │   ├── pre-receive.sample
    │   └── update.sample
    ├── info
    │   └── exclude
    ├── objects
    │   ├── info
    │   └── pack
    └── refs
        ├── heads
        └── tags

  1. 添加文件
$ vim readme.txt
# Git is a version control system.
# Git is free software.
$ git add readme.txt
$ git commit -m "wrote a readme file"
  1. 修改文件
$ vim readme.txt
# Git is a distributed version control system.
# Git is free software.
$ git status
# 查看当前工作区状态
$ git diff
#查看具体改动内容
  1. 查看历史提交信息
$ git log
# 简化版本
$ git log --pretty=oneline
  1. 恢复到某个快照(commit)版本

HEAD就是指针(commit_id)

  • HEAD:当前版本
  • HEAD^:上一个版本
  • HEAD^:上上一个版本
  • HEAD~100:往前数100个版本
$ git reset --hard HEAD^

需要返回最新版本时,执行git reflog查看历史提交记录

$ git reflog
$ git reset --hard commit_id
  1. 工作区和暂存区
20220704221530-2022-07-04-22-15-30

git add之后的修改不会被commit,每次修改完必须add到stage区域,才能别commit

  1. 撤销更改
# 撤销工作区的更改(修改文件后未进行add)
$ git checkout -- <file>

# 撤销stage区域的更改(修改文件后进行了add)
$ git reset HEAD <file>
$ git checkout -- <file>
  1. 删除文件

当在workspace中删除了某个文件时,需要推送此修改到仓库

$ git rm <file>
$ git commit -m "xxxx"

# 如果误删除,就用checkout恢复
$ git checkout -- <file>

六、远程仓库的使用

使用gitee创建测试仓库,ssh登录

# 关联本地仓库 <--> 远程仓库
$  git remote add origin git@gitee.com:weboob/gittest.git

# 推送分支master到远程
$ git push -u origin master

# 后续推送
$ git push origin master

# 删除关联仓库信息(先查看已绑定信息)
$ git remote -v
#origin  git@gitee.com:weboob/gittest.git (fetch)
#origin  git@gitee.com:weboob/gittest.git (push)

$ git remote rm origin

origin 是远程仓库的名字,后续所有的操作都是使用这个别名。

# 复制远程仓库
$ git clone git@gitee.com:weboob/gittest.git

七、分支的管理

分支的切换本质上是指针的变动,所以很快 20220705134842-2022-07-05-13-48-42

image.png-2022-07-05-13-49-44
20220705135024-2022-07-05-13-50-24

1.分支切换

# -b 参数代表创建并立即切换,相当于以下两条命令
# git branch dev
# git checkout dev
$ git checkout -b dev

# 新版本的git支持switch切换命令
# 创建并切换到dev
$ git switch -c dev
# 单独切换到dev
$ git switch master

# 查看当前所在分支
$ git branch

# 合并其他分支到当前分支(dev --> master)
# 先切换到 master 再 merge
$ git checkout master
$ git merge dev

# 删除合并后的 dev 分支
$ git branch -d dev

小结:

查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>或者git switch <name>
创建+切换分支:git checkout -b <name>或者git switch -c <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>


2. 冲突问题

当两个以上分支,同时修改了一处,在合并时会导致合并冲突。需要修改文件中的冲突部分

Git用<<<<<<<=======>>>>>>>标记出不同分支的内容

然后再次合并。

合并前: 20220705153001-2022-07-05-15-30-01


合并后: 20220705153229-2022-07-05-15-32-29

# 查看分支并情况
$ git log --graph --pretty=oneline --abbrev-commit
# *   dca33b0 (HEAD -> master) conflict fixed
# |\  
# | * bad4407 (feature1) AND simple
# * | de9ec49 & simple
# |/  
# * e52f88b branch test
# * 4bb1906 (origin/master) del text2.txt
# * c19e402 add test2.txt
# * 6f1afc4 del test.txt
# * b8bb1e8 add test.txt
# * 4d35d72 understand how stage works
# * 14334e0 append GPL
# * ba421f8 add distributed
# * 37f1b49 wrote a readme file

# 删除多余分支
$ git branch -d feature1

3. 使用 --no-ff 方式合并分支

普通的合并分支使用 Fast forward 的方式,如果删除分支会丢失分支信息。可以指定 --no-ff参数,在merge时生成新的commit

# 创建新分支
$ git switch -c dev

# 修改内容
$ vim readme.txt

# 提交信息
$ git add readme.txt
$ git commit -m "add merge"

# 返回master
$ git switch master

# 准备合并dev分支
$ git merge --no-ff -m "merge with no-ff" dev

最后因为要生成一个commit,所以指定了 -m 参数

# 查看分支合并情况
$ git log --graph --pretty=oneline --abbrev-commit

分支管理策略

20220705160625-2022-07-05-16-06-25

master分支只用来发布新的稳定版本。日常开发发布到dev。小组成员基于dev,新建自己的开发分支
合并分支时使用 --no-ff参数,方便保留历史记录

4. Bug分支(临时插队任务)

当有临时插队任务,比如:紧急修复bug,但是自己的分支工作尚未完全做完无法commit。这样可以临时stash工作区和暂存区。等以后再恢复现场。

# 暂存当前工作状态
$ git stash

# 列出已存的工作状态
$ git stash list

# 恢复 stash
$ git stash apply
# 删除 已保存的 stash
$ git stash drop

# 恢复并删除 stash
$ git stash pop

# 恢复指定的 stash
$ git stash apply stash@{0}

通过从master创建bug分支,并修复commit、merge到master后,发现dev分支同样存在这个bug。这是无需再次修改源文件,只需将master上提交的bug的commit,复制(cherry-pick)到dev分支即可。

$ git checkout master
$ git checkout -b issue-101
$ git add xxx
$ git commit -m "xxxxxx"
$ git switch master
$ git merge --no-ff -m "xxxx" issue-101
$ git branch -d issue-101
# 假设修复bug的commit_id为:4c805e2
$ git switch dev
$ git cherry-pick 4c805e2

后记:在修复bug时需要新建bug分支,然后合并,删除。多分支之间同一bug的修复用cherry-pick同步。

5. Feature 分支

新功能的开发也跟bug修复一样要有自己的分支(feature-xxx)

# 创建新分支
$ git switch -c feature-xxx

$ git add xxxx
$ git commit -m "xxxx"

$ git switch dev

开发完准备合并时,接到消息 不要这个功能了。执行删除分支命令,需要使用 强制删除 命令才可以

# 这样会有警告,分支内容尚未合并
$ git branch -d feature-xxx

# 强制删除分支
$ git branch -D feature-xxx

6. 多人协作

# 查看建立连接的远程仓库的名称
$ git remote

# 查看具体的仓库地址
$ git remote -v

# 推送dev分支到远程
$ git push origin dev

一般来说,分支的推送看自己的需求: master主分支,需要时刻推送;dev开发分支,团队所有成员都在上面工作,一般也需要推送;bug分支和feature分支,视需求而定。

如果他人比自己先建立dev分支,并推送了修改文件,而我们也建立了这个分支并推送了修改过的相同文件,这时就会出现conflict,需要在本地解决冲突,再推送。

# user1创建本地dev分支,并关联远程dev分支
$ git checkout -b dev origin/dev

# user2 需要建立链接
$ git branch --set-upstream-to=origin/dev dev

# 拉取远程数据
$ git pull

# 修改冲突后,再提交
$ git push origin dev

7. 整理分叉(Rebase)

感觉没啥意思,拯救强迫症???

$ git rebase

八、标签管理

给某个commit起个有意义的名字的指针就是tag

# 当前提交添加标签
$ git tag xxx

# 查看已有标签
$ git tag

# 给指定commit 添加标签
$ git tag xxx commit_id

# 查看某个tag的commit的具体信息
$ git show <tagname>

# 提交带说明的tag
$ git tag -a <tagname> -m "tag message"

# 删除指定标签
$ git tag -d <tagname>

# 推送某个标签到远程
$ git push origin <tagname>

# 推送全部标签到远程
$ git push origin --tags

# 删除远程标签分两部(1:删除本地标签;2:推送状态到远程)
$ git tag -d ex_tag
$ git push origin :refs/tags/ex_tag

九、使用github或gitee的一般流程

先fork别人的repository到自己账号下面,然后clone自己账号下面的repository到本地,结构如下:

20220706222429-2022-07-06-22-24-29

可以同时关联多个远程库(通过别名区分)

# 关联两个库
$ git remote add github git@github.com:xxxx/xxx.git
$ git remote add gitee git@gitee.com:xxxx/xxx.git

# 推送github
$ git push github master

# 推送gitee
$ git push gitee master

效果如下:

20220706223324-2022-07-06-22-33-24

十、自定义git

1. 定义忽略版本控制的文件

通过 .gitignore 文件,记录需要放手的文件。在线编辑

忽略文件的原则:

  • 操作系统自动生成的文件(缩略图)
  • 程序编译中间文件(.class),或者能通过程序运行自动生成的文件
  • 忽略带有敏感信息的文件(带明文密码的配置文件)

内容范例:

# 这是注释,可以分类标记;
# 文件可以直接写全称,标注单个文件
Thumbs.db
Desktop.ini

# 也可以使用通配符标注一类文件
*.class
# 排除 `.` 开头的文件
.*

# 也可以直接忽略文件夹
dist
build

# 规则例外的单独文件
!.gitignore

如果自己编写的.gitignore文件有问题,可以强制更新文件:

$ git add -f filename

# 检查配置文件错误
$ git check-ignore -v filename

2. git的其他配置

–global 参数对当前用户所有仓库都起作用
每个repository的配置文件在:.git/config
Git的配置文件在:~/.gitconfig

# 开启颜色配置
$ git config --global color.ui true

# 配置命令别名(status --> st)
$ git config --global alias.st status

# 配置命令别名(打印好看的图形化log)
$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

3. 搭建自己的Git服务器

system:Debian/Ubuntu/Deepin

# 1. 安装git
$ sudo apt install git

# 2. 创建用户
# 禁止登陆shell
$ sudo adduser git
$ sudo vim /etc/passwd
# git:x:1001:1001:,,,:/home/git:/bin/bash --> git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

# 3. 设置登录证书(每行一个)
$ sudo vim ~/git/.ssh/autorized_keys
# adfeiaidfoeasdfefoadfeoasdjfe...
# adifekdikfjeaooisidfjeojfasda...

# 4. 初始化 Repository,并更改用户
$ cd /srv
$ sudo git init --bare sample.git
$ sudo chown -R git:git sample.git

# 5. clone 远程仓库到本地
$ git clone git@server:/srv/sample.git

批量公钥管理:Gitosis 细粒度权限管理:Gitolite

  1. 参考文献1-图片解析git工作原理
  2. 参考文献2-廖雪峰关于git的文章

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注