一、Git是什么
Git是一个免费开源的分布式版本控制系统,有Linux Torvaldds为帮助管理Linux内核开发。
二、Git与SVN、CVS的区别
- SVN/CVS,集中式存储,有中央服务器,必须联网才能使用,如果中央服务器瘫痪,任何人都应用不了(基于文件差异的版本控制)
- Git 分布式存储,没有中央服务器,每个人的副本的都是完整的。(版本文件快照)
三、Git的工作流程
- 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的使用
- 新建目录,初始化为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
- 添加文件
$ vim readme.txt
# Git is a version control system.
# Git is free software.
$ git add readme.txt
$ git commit -m "wrote a readme file"
- 修改文件
$ vim readme.txt
# Git is a distributed version control system.
# Git is free software.
$ git status
# 查看当前工作区状态
$ git diff
#查看具体改动内容
- 查看历史提交信息
$ git log
# 简化版本
$ git log --pretty=oneline
- 恢复到某个快照(commit)版本
HEAD就是指针(commit_id)
HEAD
:当前版本HEAD^
:上一个版本HEAD^
:上上一个版本HEAD~100
:往前数100个版本
$ git reset --hard HEAD^
需要返回最新版本时,执行git reflog
查看历史提交记录
$ git reflog
$ git reset --hard commit_id
- 工作区和暂存区
git add
之后的修改不会被commit
,每次修改完必须add到stage区域,才能别commit
- 撤销更改
# 撤销工作区的更改(修改文件后未进行add)
$ git checkout -- <file>
# 撤销stage区域的更改(修改文件后进行了add)
$ git reset HEAD <file>
$ git checkout -- <file>
- 删除文件
当在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
七、分支的管理
分支的切换本质上是指针的变动,所以很快
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用
<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容
然后再次合并。
合并前:
合并后:
# 查看分支并情况
$ 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
分支管理策略
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到本地,结构如下:
可以同时关联多个远程库(通过别名区分)
# 关联两个库
$ 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
效果如下:
十、自定义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