这个参考了python–100days
Git本地操作
可以使用下面的命令将一个文件夹变成Git仓库。
git init
当你完成了上述操作后,本地目录就变成了下面的样子,下图左边是你的工作区(working)(正在操作的工作目录),而右边是你的本地仓库(head),中间是工作区和本地仓库之间的暂存区(stage)(也称为缓存区)。
提示:用
ls -la
查看所有文件会发现在执行完上面的命令后,文件夹下多了一个名为.git
的隐藏文件夹,这个就是本地的Git版本仓库。
通过git add
可以将指定的文件或所有文件添加到暂存区。
git add <file>
git add .
这个时候使用下面的命令可以查看工作区、暂存区和本地仓库的状态。
git status
提示:如果不希望将文件添加到暂存区,可以按照提示,使用
git rm --cached <file>
命令将文件从暂存区放回到工作区。
如果这个时候对工作区的文件又进行了修改使得工作区和暂存区的内容并不相同了,再次执行git status
可以看到哪个或哪些文件被修改了,如果希望用暂存区的内容恢复工作区,可以使用下面的命令。
git restore <file>
git restore .
注意:上面的命令目前仍然处于试验性阶段,在Git较早的版本中对应的命令是
git checkout -- <file>
。由于git checkout
这个命令还可以用于切换分支,容易引起混淆,所以Git最新版本中将这个命令的两项功能分别赋予两个新的命令,一个就是上面的git restore
,另一个是git switch
。
如果第一次使用Git,需要配置用户名和邮箱,然后才能将代码提交到仓库。
git config --global user.name "jackfrued"
git config --global user.email "jackfrued@126.com"
提示:可以用
git config --list
来查看Git的配置信息。
通过下面的命令可以将暂存区的内容纳入本地仓库,
git commit -m '本次提交的说明'
可以通过git log
查看每次提交对应的日志。
git log
git log --graph --oneline --abbrev-commit
Git服务器概述
Git不像SVN那样一定需要中央服务器才能工作,上面我们演示的版本控制操作都是在本地执行的,但是对于企业开发多人协作这样的场景还是需要中央服务器的支持。通常,企业可以选择使用代码托管平台(如GitHub)或自己搭建Git私服的方式来建立中央服务器(版本仓库),当然大多数的企业更倾向于后者。Github创办于2008年4月,目前是全世界最大的代码托管平台,支持企业用户(可以创建私有仓库,私有仓库内容不对外界公开)和普通用户(受限的使用私有仓库,不受限的使用公开仓库,公开仓库内容对他人可见)。Github上面代码库惊人的增长速度证明了它是非常成功的,在2018年6月被微软以75亿美元的天价收购。
国内也有不少类似Github的代码托管平台,最有名的当属码云和CODING,目前码云和CODING对注册用户都提供了受限的使用私有仓库的功能,支持Pull Request(一种对话机制,可以在提交你的工作成果时让相关人员或团队注意到这件事情),同时还提供了对缺陷管理、Webhook等功能支持,这些使得版本控制系统还具备了缺陷管理和持续集成的能力。当然,很多公司都不愿意将自己的商业代码托管于别人的平台,这样的公司可以用Gitlab来搭建公司内部的Git私服,具体的做法在下一章为大家介绍。
这里我们直接以码云为例来说明使用Git服务器的一些注意事项。首先需要在码云上注册账号,当然也可以使用第三方登录(github账号、微信账号、新浪微博账号、CSDN账号等),登录成功后就可以创建项目,创建项目几乎是“傻瓜式”的,无需赘述,我们只对几个地方加以说明。
-
创建项目时不建议勾选如下图所示的这些选项,编程语言可以暂时不做选择,而
.gitignore
模板也可以稍后自己编写或者通过更专业的工具(如:http://gitignore.io/网站)自动生成。 -
添加项目成员。创建项目后,可以在项目的“设置”或“管理”中找到“成员管理”功能,这样就可以将其他开发者设置为项目团队的成员,项目成员通常分为“所有者”、“管理者”、“普通成员”和“受限成员”几种角色。
-
项目的分支。创建项目后,项目只有一个默认的master分支,应该将该分支设置为“保护分支”来避免项目管理者之外的成员修改该分支(不可直接提交)。当然,如果需要我们也可以在线创建新的代码分支。
-
设置公钥实现免密访问。在项目的“设置”或“管理”中我们还可以找到“部署公钥管理”的选项,通过添加部署公钥,可以通过SSH(安全远程连接)的方式访问服务器而不用每次输入用户名和口令。可以使用
ssh-keygen
命令来创建密钥对。ssh-keygen -t rsa -b 2048 -C "your_email@example.com"
说明:上面命令生成的密钥对在
~/.ssh
目录下,公钥文件默认的名字为id_rsa.pub
,可以通过cat id_rsa.pub
来查看自己的公钥。Windows用户在安装Git工具后,可以通过Git Bash来输入上面的命令。
Git远程操作
拥有了Git服务器之后,我们就可以通过Git的远程操作将自己的工作成果推到服务器的仓库中,也可以将他人的工作成果从服务器仓库更新到本地。我们以刚才在码云上创建的仓库(仓库名为python
)为例来说明如何进行远程操作。可以在如下所示的页面上找到仓库的地址(URL),如果配置了SSH Key就使用SSH方式访问仓库,否则就用HTTPS方式,后者需要在进行远程操作时提供用户名和口令。
-
添加远程仓库(Git服务器)。
git remote add origin git@gitee.com:jackfrued/python.git
其中
git@gitee.com:jackfrued/python.git
是上图中显示的仓库的URL,而前面的origin
是替代这个冗长的URL的字符串,简单的说origin
就是服务器上仓库的别名(如果有多个Git服务器,这个简短的名字也会有多个)。可以用git remote -v
来查看已经指定的Git服务,也可以用git remote remove
来删除指定的Git服务器。 -
将本地代码(工作成果)推送到远程仓库。
git push -u origin master:master
其中,
-u
是--set-upstream
的缩写,用来指定推送的服务器仓库,后面的origin
就是刚才给仓库起的简短的别名,冒号前面的master
是本地分支名,冒号后面的master
是远程分支名,如果本地分支master
已经和远程分支master
建立过关联,则冒号以及后面的部分可以省略。 -
从远程仓库取回代码。
git pull origin master
Git分支操作
-
创建和切换分支。下面的命令创建了名为
dev
的分支并切换到该分支。git branch <branch-name> git switch <branch-name>
或
git switch -c <branch-name>
注意:在之前的Git版本中,切换分支使用
git checkout <branch-name>
命令,也可以通过git checkout -b <branch-name>
来创建并切换分支。git switch
命令目前仍然处于试验性阶段,但很明显这个命令更加清晰的表达了它要做的事情。 -
关联远程分支。例如:如果当前所在的分支还没有关联到远程分支,可以使用下面的命令为它们建立关联。
git branch --set-upstream-to origin/develop
如果需要为指定的分支关联远程分支,可以如下操作。
git branch --set-upstream-to origin/develop <branch-name>
提示:上面的操作假设Git服务器上存在名为
develop
的分支,--set-upstream-to
可以缩写为-u
。当然,在创建分支时,如果使用了
--track
参数,也可以直接指定与本地分支关联的远程分支,如下所示。git branch --track <branch-name> origin/develop
如果需要解除本地分支与远程分支的关联,可以使用下面的命令。
git branch --unset-upstream <branch-name>
-
分支合并。例如在
dev
分支上完成开发任务之后,如果希望将dev
分支上的成果合并到master
,可以先切回到master
分支然后使用git merge
来做分支合并,合并的结果如下图右上方所示。git switch master git merge --no-ff dev
使用
git merge
合并分支时,默认使用Fast Forward
合并,这意味着如果删除了分支,分支上的信息就全都丢掉了,如果希望将分支上的历史版本保留下来,可以使用--no-ff
参数来禁用Fast Forward
。在合并分支时,没有冲突的部分Git会做自动合并。如果发生了冲突(如
dev
和master
分支上都修改了同一个文件),会看到CONFLICT (content): Merge conflict in <filename>. Automatic merge failed; fix conflicts and then commit the result
(自动合并失败,修复冲突之后再次提交)的提示,这个时候我们可以用git diff
来查看产生冲突的内容。解决冲突通常需要当事人当面沟通之后才能决定保留谁的版本,冲突解决后需要重新提交代码。 -
分支变基。分支合并操作可以将多个分支上的工作成果最终合并到一个分支上,但是再多次合并操作之后,分支可能会变得非常的混乱和复杂,为了解决这个问题,可以使用
git rebase
操作来实现分支变基。如下图所示,当我们希望将master
和dev
上的工作成果统一到一起的时候,也可以使用变基操作。git rebase master git switch master git merge dev
当我们在
dev
分支执行git rebase
命令时,将首先计算dev
分支和master
分支的差集,然后应用该差集到dev
分支,最后我们切回到master
分支并执行操作合并,这样就看到了如上图右下方所示的干净的分支。 -
删除分支。删除分支可以使用
git branch
加上-d
参数,如果分支上的工作成果还没有合并,那么在删除分支时会看到error: The branch '<branch-name>' is not fully merged.
这样的错误提示。如果希望强行删除分支,可以使用-D
参数。删除分支的操作如下所示。git branch -d <branch-name> error: The branch '<branch-name>' is not fully merged. If you are sure you want to delete it, run 'git branch -D <branch-name>'. git branch -D <branch-name>
如果要删除远程分支,可以使用下面的命令,但是请慎重的操作。
git branch -r -d origin/develop git push origin :develop
或者
git push origin --delete develop
Git其他操作
-
git fetch
:下载远程仓库的所有变动,可以将远程仓库下载到一个临时分支,然后再根据需要进行合并操作,git fetch
命令和git merge
命令可以看作是之前讲的git pull
命令的分解动作。git fetch origin master:temp git merge temp
-
git diff
:常用于比较工作区和仓库、暂存区与仓库、两个分支之间有什么差别。 -
git stash
:将当前工作区和暂存区发生的变动放到一个临时的区域,让工作区变干净。这个命令适用于手头工作还没有提交,但是突然有一个更为紧急的任务(如线上bug需要修正)需要去处理的场景。git stash git stash list git stash pop
-
git reset
:回退到指定的版本。该命令主要有三个参数,如下图所示。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KDj7ope-1589958632816)(./res/git-reset.png)]
-
git cherry-pick
:挑选某个分支的单次提交并作为一个新的提交引入到你当前分支上。 -
git revert
:撤回提交信息。 -
git tag
:经常用于查看或新增一个标签。
Git工作流程(分支管理策略)
既然Git是团队开发必备的工具,那么在团队协作时就必须有一个规范的工作流程,这样才能让团队高效的工作,让项目顺利的进展下去,否则工具再厉害但团队成员各自为战,冲突就会无处不在,协作更加无从谈起。我们仍然以刚才码云上创建的python
项目为例,来说明Git的分支管理策略。
Github-flow
-
克隆服务器上的代码到本地。
git clone git@gitee.com:jackfrued/python.git
-
创建并切换到自己的分支。
git switch -c <branch-name>
或
git checkout -b <branch-name>
-
在自己的分支上开发并在本地做版本控制。
-
将自己的分支(工作成果)推到服务器。
git push origin <branch-name>
-
在线发起一次合并请求(通常称之为Pull Request,有的地方称为Merge Request),请求将自己的工作成果合并到
master
分支,合并之后可以删除该分支。
上面这种分支管理策略就是被称为github-flow或PR的流程,它非常简单容易理解,只需要注意以下几点:
master
的内容都是可以进行发布的内容(不能直接在master
上进行修改)。- 开发时应该以
master
为基础建立新分支(日常开发任务在自己的分支上进行)。 - 分支先在本地实施版本控制,然后以同名分支定期向服务器进行push操作。
- 开发任务完成后向
master
发送合并请求。 - 合并请求通过审查之后合并到
master
,并从master
向正式环境发布。
当然,github-flow的缺点也很明显,master
分支默认就是当前的线上代码,但是有的时候工作成果合并到master
分支,并不代表它就能立刻发布,这样就会导致线上版本落后于master
分支。
Git-flow
除了上述的github-flow分支管理策略外,还有一种名为git-flow的分支管理策略,它也是大多数公司愿意使用的一套流程。Git-flow借鉴了中央集权型版本控制系统的长处,为团队内部统一建立、合并和关闭分支的方法,如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-skC6uzZ8-1589958632820)(./res/git-flow.png)]
在这种模式下,项目有两个长线分支,分别是master
和develop
,其他都是临时的的辅助分支,包括feature
(开发特定功能的分支,开发结束后合并到develop
)、release
(从develop
分离出来的为发布做准备的分支,发布结束后合并到master
和develop
)和hotfix
(产品发布后出现问题时紧急建立的分支,直接从master
分离,问题修复后合并到master
并打上标签,同时还要合并到develop
来避免将来的版本遗漏了这个修复工作,如果此时有正在发布中的release
分支,还要合并到release
分支)。具体的实施过程如下所示:
-
最开始的时候只有
master
和develop
分支,如上图左侧所示。 -
从
develop
分支创建feature
分支(上图右上),工作完成后将工作成果合并到develop
分支(上图右中)。创建
feature
分支:git switch -c feature/user develop
或
git checkout -b feature/user develop
接下来就是在
feature
分支上进行开发并实施版本控制,这一段如何操作我们就不再赘述了。工作完成后,将feature
分支合并到develop
分支:git checkout develop git merge --no-ff feature/user git branch -d feature/user git push origin develop
-
从
develop
分支创建release
分支,发布结束后合并回master
和develop
分支。创建
release
分支:git checkout -b release-0.1 develop git push -u origin release-0.1 ... ... ... git pull git commit -a -m "............"
将
release
分支合并回master
和develop
分支:git checkout master git merge --no-ff release-0.1 git push git checkout develop git merge --no-ff release-0.1 git push git branch -d release-0.1 git push --delete release-0.1 git tag v0.1 master git push --tags
-
从
master
分支创建hotfix
分支,在修复bug后合并到develop
和master
分支(上图右下)。创建
hotfix
分支:git checkout -b hotfix-0.1.1 master git push -u origin hotfix-0.1.1 ... ... ... git pull git commit -a -m "............"
将
hotfix
分支合并回develop
和master
分支。git checkout master git merge --no-ff hotfix-0.1.1 git push git checkout develop git merge --no-ff hotfix-0.1.1 git push git branch -d hotfix-0.1.1 git push --delete hotfix-0.1.1 git tag v0.1.1 master git push --tags
Git-flow流程比较容易控制各个分支的状况,但是在运用上github-flow要复杂得多,因此实际使用的时候通常会安装名为gitflow
的命令行工具(Windows环境的Git自带了该工具)或者使用图形化的Git工具(如:SmartGit、SourceTree等)来简化操作,具体的可以参考《git-flow 的工作流程》一文,因为这篇文章写得已经很好了,本文不再进行赘述。