常见版本控制器

集中式版本控制器

CSV/SVN

  • 速度慢,必须联网
  • 只有⼀个中央数据仓库,如果中央数据仓库挂了或者⽆法访问,所有的使用者无法使⽤SVN,无法法进行提交或备份操作

分布式版本控制器

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目

Git一开始是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件

Git优点:

  • 无中央服务器,每个人的电脑都是一个完整的版本库
  • 完全性能更高
  • 通常有一台充当“中央服务器”的电脑,仅仅作为方便“交换”大家的修改

Git和SVN的区别:

  • Git 是分布式的,SVN 不是
  • Git 把内容按元数据方式存储,而 SVN 是按文件
  • Git 分支和 SVN 的分支不同
  • Git 没有一个全局的版本号,而 SVN 有
  • Git 的内容完整性要优于 SVN:Git 的内容存储使用的是 SHA-1 哈希算法

Git - 图1

Git安装

Git官网下载https://git-scm.com/downloads

  • yum安装git
  1. [root@server1 ~]# yum install git -y
  • 配置本地用户信息
  1. [root@server1 ~]# git config --global user.name "sy"
  2. [root@server1 ~]# git config --global user.email "sy@qq.com"
  3. [root@server1 ~]# git config --global color.ui true
  4. [root@server1 ~]# git config --list
  5. user.name=sy
  6. user.email=sy@qq.com
  7. color.ui=true
  • 创建并初始化版本库
  1. [root@server1 ~]# mkdir my_git
  2. [root@server1 ~]# cd my_git/
  3. [root@server1 my_git]# git init
  4. 初始化空的 Git 版本库于 /root/my_git/.git/
  5. [root@server1 my_git]# ls -a
  6. . .. .git
  7. [root@server1 my_git]# ls .git/
  8. branches config description HEAD hooks info objects refs

Git介绍

Git的组织结构如下图所示:

Git - 图2

  • 工作目录

    • 当前所在的目录就是工作目录
  • 暂存区域

    • .git不算⼯作区,只是git的版本库
    • 版本库中只有暂存区和自动创建的master分⽀及指向master的⼀个指针HEAD
    • git跟踪的是每次修改而不是文件,如果不将修改添加到暂存区是无法进行提交的
  • .git文件夹中的文件介绍
    1. branches # 分支目录
    2. config # 定义项目特有的配置选项
    3. description # 仅供git web程序使用
    4. HEAD # 指示当前的分支
    5. hooks # 包含git钩子文件
    6. info # 包含一个全局排除文件
    7. objects # 本地仓库,存放所有的数据内容,有info和pack两个文件夹
    8. refs # 存放指向数据(分支)的提交对象的指针
    9. index # 保存暂存信息,在执行git init的时候,这个文件还没有
  • 远程仓库:Github、Gitee

常规使用

日常使用的命令如下图所示:

Git - 图3

  • 添加文件到仓库中,语法:git add 文件名
  1. [root@server1 my_git]# echo "hello world" > README.txt
  2. [root@server1 my_git]# git add README.txt
  • 查看Git状态,语法:git status
  1. [root@server1 my_git]# git status
  2. # 位于分支 master
  3. #
  4. # 初始提交
  5. #
  6. # 要提交的变更:
  7. # (使用 "git rm --cached <file>..." 撤出暂存区)
  8. #
  9. # 新文件: README.txt
  10. #
  • 提交文件到仓库,语法:git commit -m "注释内容"
  1. [root@server1 my_git]# git commit -m "write a README.txt"
  2. [master(根提交) 0943734] write a README.txt
  3. 1 file changed, 1 insertion(+)
  4. create mode 100644 README.txt
  5. [root@server1 my_git]# git status
  6. # 位于分支 master
  7. 无文件要提交,干净的工作区
  • 修改文件,再次提交到仓库,语法:git commit -a -m "注释内容"
  1. [root@server1 my_git]# echo "hello linux" > README.txt
  2. [root@server1 my_git]# git status
  3. # 位于分支 master
  4. # 尚未暂存以备提交的变更:
  5. # (使用 "git add <file>..." 更新要提交的内容)
  6. # (使用 "git checkout -- <file>..." 丢弃工作区的改动)
  7. #
  8. # 修改: README.txt
  9. #
  10. 修改尚未加入提交(使用 "git add" 和/或 "git commit -a"
  11. [root@server1 my_git]# git commit -a -m "modify a README.txt"
  12. [master 0ef4b46] modify a README.txt
  13. 1 file changed, 1 insertion(+), 1 deletion(-)
  14. [root@server1 my_git]# git status
  15. # 位于分支 master
  16. 无文件要提交,干净的工作区
  • git commit 命令的-a选项可将所有被修改或者已删除的且已经被git管理的文档提交到仓库中
  • 不能提交新文件,对于新文件还是需要先使用git add再使用git commit
  • 查看文件内容改动情况,语法:git diff 文件名
  1. [root@server1 my_git]# echo "hello python" > README.txt
  2. [root@server1 my_git]# git diff README.txt
  3. diff --git a/README.txt b/README.txt
  4. index ce09bf3..0ea61c1 100644
  5. --- a/README.txt
  6. +++ b/README.txt
  7. @@ -1 +1 @@
  8. -hello linux
  9. +hello python

PS:只能查看当前未到仓库中的文件已经到仓库中的同名文件进行对比

-号代表与上一个文件相比少的内容

+号代表与上一个文件相比多的内容

  • 查看历史记录

    • git log:详细展示
    • git log --oneline:精简展示
    • git reflog:能获取历史版本号
  1. [root@server1 my_git]# git log
  2. commit 0ef4b466581f3675b708db7e2d0d25b232c4c143
  3. Author: sy <sy@qq.com>
  4. Date: Mon Mar 7 01:20:08 2022 +0800
  5. modify a README.txt
  6. commit 09437342b5e6f31ebe6450906a7f6f057975585b
  7. Author: sy <sy@qq.com>
  8. Date: Mon Mar 7 01:16:39 2022 +0800
  9. write a README.txt
  1. [root@server1 my_git]# git log --oneline
  2. 0ef4b46 modify a README.txt
  3. 0943734 write a README.txt
  1. [root@server1 my_git]# git reflog
  2. 0ef4b46 HEAD@{0}: commit: modify a README.txt
  3. 0943734 HEAD@{1}: commit (initial): write a README.txt
  • 删除文件,语法:git rm 文件名(不能删除在暂存区中的文件)
  1. [root@server1 my_git]# git rm README.txt
  2. rm 'README.txt'
  3. [root@server1 my_git]# git commit -m "delete a README.txt"
  4. [master 02cdd1a] delete a README.txt
  5. 1 file changed, 1 deletion(-)
  6. delete mode 100644 README.txt
  7. [root@server1 my_git]# git status
  8. # 位于分支 master
  9. 无文件要提交,干净的工作区

分支

分支介绍

  • 分支就是平行空间,假设你在某个手机系统研发拍照功能,代码已经完成了80%,但如果将这不完整的代码直接提交到git仓库中,又有可能影响到其他人的工作,此时我们便可以在该软件的项目之上创建一个名叫拍照的分支,这种分支只会属于你自己,而其他人看不到,等代码编写完成后再与原来的项目主分支合并即可,这样既能保证代码不丢失,又不影响其他人工作

  • 一般在实际的项目开发中,尽量保持master分支是非常稳定的,仅用于发布新版本,平时不要随便直接修改里面的数据文件,而工作的时候则可以新建不同的工作分支,等到工作完成后再合并到master分支上面,所以团队的合作分支看起来会像很多树枝一样

Git - 图4

命令集合

查询分支

  1. # 列出所有本地分⽀
  2. $ git branch
  3. # 列出所有远程分⽀
  4. $ git branch -r
  5. # 列出所有本地分⽀和远程分⽀
  6. $ git branch -a

新建分支

  1. # 新建⼀个分⽀,但依然停留在当前分⽀
  2. $ git branch [branch-name]
  3. # 新建⼀个分⽀,并切换到该分⽀
  4. $ git checkout -b [branch]
  5. # 新建⼀个分⽀,指向指定commit
  6. $ git branch [branch] [commit]
  7. # 新建⼀个分⽀,与指定的远程分支建立追踪关系
  8. $ git branch --track [branch] [remote-branch]

切换分支

  1. # 切换到指定分⽀,并更新⼯作区
  2. $ git checkout [branch-name]
  3. # 切换到上⼀个分⽀
  4. $ git checkout -

合并分支

  1. # 合并指定分⽀到当前分⽀
  2. $ git merge [branch]
  3. # 选择⼀个commit,合并进当前分⽀
  4. $ git cherry-pick [commit]

示例:

  1. [root@server1 my_git]# git branch
  2. master
  3. * photo
  4. [root@server1 my_git]# echo "hello world" > test.txt
  5. [root@server1 my_git]# git add test.txt
  6. [root@server1 my_git]# git commit -m "add a test.txt"
  7. [root@server1 my_git]# ls
  8. test.txt
  9. [root@server1 my_git]# git checkout master
  10. 切换到分支 'master'
  11. [root@server1 my_git]# echo "hello linux" > TEST.txt
  12. [root@server1 my_git]# git add TEST.txt
  13. [root@server1 my_git]# git commit -m "add a TEST.txt"
  14. [root@server1 my_git]# ls
  15. TEST.txt
  16. # 将photo合并到当前分支即master分支
  17. [root@server1 my_git]# git merge photo
  18. Merge made by the 'recursive' strategy.
  19. test.txt | 1 +
  20. 1 file changed, 1 insertion(+)
  21. create mode 100644 test.txt
  22. [root@server1 my_git]# ls
  23. test.txt TEST.txt

追踪分支

  1. # 建⽴追踪关系,在现有分⽀与指定的远程分⽀之间
  2. $ git branch --set-upstream [branch] [remote-branch]

删除分支

  1. # 删除分⽀
  2. $ git branch -d [branch-name]
  3. # 删除远程分⽀
  4. $ git push origin --delete [branch-name]
  5. $ git branch -dr [remote/branch]

筛选分支

  1. # 检出版本v2.0
  2. $ git checkout v2.0
  3. # 从远程分⽀develop创建新本地分⽀devel并检出
  4. $ git checkout -b devel origin/develop
  5. # 检出head版本的README⽂件(可⽤于修改错误回退)
  6. $ git checkout -- README

标签

  • 给状态新建标签
  1. # 给当前状态打标签
  2. $ git tag -a v1.0 -m " version 1.0"
  3. # 指定某次状态打标签
  4. $ git tag -a v2.0 [哈希值] -m "version 2.0"
  • 给commit新建标签
  1. # 新建⼀个tag在当前commit
  2. $ git tag [tag]
  3. # 新建⼀个tag在指定commit
  4. $ git tag [tag] [commit]
  • 查看标签信息
# 查看所有标签信息
$ git tag

# 查看指定标签信息
$ git show v1.0
  • 以标签回滚
git reset --hard v2.0
  • 删除标签
# 删除本地标签
$ git tag -d v1.0

# 删除远程标签
$ git push origin :refs/tags/[tagName]
  • 提交标签
# 提交指定tag
$ git push [remote] [tag]

# 提交所有tag
$ git push [remote] --tags
  • 新建分支指定标签
$ git checkout -b [branch] [tag]

远程同步

# 下载远程仓库的所有变动
$ git fetch [remote]

# 显示所有远程仓库
$ git remote -v

# 显示某个远程仓库的信息
$ git remote show [remote]

# 增加⼀个新的远程仓库,并命名
$ git remote add [shortname] [url]

# 取回远程仓库的变化,并与本地分⽀合并
$ git pull [remote] [branch]

# 推送本地指定分⽀到远程仓库
$ git push [remote] [branch]

# 推送所有分⽀到远程仓库
$ git push [remote] --all

# 强⾏推送当前分⽀到远程仓库,即使有冲突
$ git push [remote] --force

直接下载整个仓库

[root@server1 ~]# git clone https://gitee.com/Yimoqingfeng/git_test
正克隆到 'git_test'...
Username for 'https://gitee.com': Yimoqingfeng
Password for 'https://Yimoqingfeng@gitee.com': 
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 10 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (10/10), done.
[root@server1 ~]# ls git_test/ -a
.  ..  .git  .gitignore  LICENSE

撤销回滚

# 恢复暂存区的指定⽂件到⼯作区
$ git checkout [file]

# 恢复某个commit的指定⽂件到暂存区和⼯作区
$ git checkout [commit] [file]

# 恢复暂存区的所有⽂件到⼯作区
$ git checkout .

# 重置暂存区的指定⽂件,与上⼀次commit保持⼀致,但⼯作区不变
$ git reset [file]

# 重置暂存区与⼯作区,与上⼀次commit保持⼀致
$ git reset --hard

# 重置当前分⽀的指针为指定commit,同时重置暂存区,但⼯作区不变
$ git reset [commit]

# 重置当前分⽀的HEAD为指定commit,同时重置暂存区和⼯作区,与指定commit⼀致
$ git reset --hard [commit]

# 重置当前HEAD为指定commit,但保持暂存区和⼯作区不变
$ git reset --keep [commit]

# 新建⼀个commit,⽤来撤销指定commit
# 后者的所有变化都将被前者抵消,并且应⽤到当前分⽀
$ git revert [commit]

# 暂时将未提交的变化移除,稍后再移⼊
$ git stash
$ git stash pop

Gitee仓库

Github仓库使用和Gitee仓库使用是相似的,由于Github对网络要求较高,因此这里使用Gitee进行实验

  • 本地仓库
[root@server1 ~]# mkdir test_git
[root@server1 ~]# cd test_git/

# 初始化本地仓库
[root@server1 test_git]# git init
初始化空的 Git 版本库于 /root/test_git/.git/

# 创建文件
[root@server1 test_git]# echo "hello" > README.md

# 存入暂存区域
[root@server1 test_git]# git add README.md 

# 提交文件到本地仓库
[root@server1 test_git]# git commit -m "add a README.md"
[root@server1 test_git]# ls
README.md

# 再创建一个新的分支photo
[root@server1 test_git]# git branch photo
[root@server1 test_git]# git checkout photo

# 创建文件
[root@server1 test_git]# echo "my photo" > photo.txt

# 存入暂存区域
[root@server1 test_git]# git add photo.txt

# 提交文件到本地仓库
[root@server1 test_git]# git commit -m "add a photo.txt"
[root@server1 test_git]# ls
photo.txt  README.md    
# master分支中的内容,在其他分支中也会存在
  • 在Gitee中创建一个新的仓库

Git - 图5

Git - 图6

  • 将本地的仓库分支推送到远程的Gitee仓库
[root@server1 test_git]# git push https://gitee.com/Yimoqingfeng/git_test photo
Username for 'https://gitee.com': Yimoqingfeng
Password for 'https://Yimoqingfeng@gitee.com': 
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 457 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: Powered by GITEE.COM [GNK-6.3]
remote: Create a pull request for 'photo' on Gitee by visiting:
remote:     https://gitee.com/Yimoqingfeng/git_test/pull/new/Yimoqingfeng:photo...Yimoqingfeng:master
To https://gitee.com/Yimoqingfeng/git_test
 * [new branch]      photo -> photo

可以看到photo分支被推送到了远程仓库,分支数变为2

Git - 图7

  • 将Gitee仓库中的内容拉取到本地仓库的master分支
[root@server1 test_git]# git pull https://gitee.com/Yimoqingfeng/git_test/ master
Username for 'https://gitee.com': Yimoqingfeng
Password for 'https://Yimoqingfeng@gitee.com': 
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.
来自 https://gitee.com/Yimoqingfeng/git_test
 * branch            master     -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 .gitignore |  13 ++
 LICENSE    | 661 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 674 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 LICENSE

可以发现master仓库中也有了远程仓库的内容

[root@server1 test_git]# git branch
* master
  photo
[root@server1 test_git]# ls -a
.  ..  .git  .gitignore  LICENSE  README.md