赞
踩
作为从一个 svn
转过来的 git
前端开发,在经历过git的各种便捷好处后,想起当时懵懂使用git的胆颤心惊:总是害怕用错指令,又或者遇到报错就慌的场景,想起当时查资料一看git指令这么多,看的头晕眼花,根本不知道从何下手。
为了给一些小白以及初学者少走点弯路,我会根据在实际开发中,可能出现的场景,用实例结合部分理论。写一篇关于git在多人开发中的操作解决指南,全文通俗易懂,很适合上手。
第一步肯定是先安装呀,直接下载到电脑,一直下一步即可,如果遇到下载失败等问题,这里直接百度即可,不做过多描述。
至于为什么要讲这一步,为了照顾到有些连这一步都不懂的小白(会的可以跳过)。假设你现在有了一个新项目,就需要在Gitee或者Github上新建一个仓库,以下拿Gitee举例(当然是Gitee是中文啦!),包括本人目前内部团队也是用的Gitee企业版。
这里只做个人新建教学,如果你是公司内部负责人,你也可以免费新建企业版本(可以最多支持5个成员,如果有需求可以自行购买,企业新建项目流程跟个人差不多)
关于下面那三个选项:初始化仓库、设置模板、选择分支模型,这里就不做设置。
创建成功后就可以看到以下内容
部分小白看到这里可能就懵了:“怎么突然多了这么多指令,我到底要做哪个?”
好,那我们一步步去理解
这里为了方便演示,我们直接初始化 readme 文件
(后续再删)
在初始化之后,会自动生成两个md文件,这里先不用管。我们直接点击克隆/下载
有些初学者想把别人的项目代码克隆到本地的时候,因为没有学过git操作,通常可能选择最直观的方式:下载ZIP!,确实是最方便的操作,但是我们这里是为了多人开发去不断修改代码并提交到仓库,所以我们要选择HTTPS/SSH去拉取代码。
这里的区别只讲操作的区别,可以看到Gitee也提示我们在使用HTTPS的时候:
使用 HTTPS 协议时,命令行会出现如下账号密码验证步骤。总结就是,如果不设置私人令牌,那你修改代码后,推送代码到仓库/分支,每次都要都要输入一次你的gitee账户密码,特别麻烦!
切换到SSH
可以看到提示:初次使用SSH需要配置。看到这里有些初学者也有点懵:“这些指令又是什么意思?”
这里解释一下什么是SSH协议作用(大概了解就行):通过SSH操作远程仓库时,gitee/github需要对你的电脑的公钥做一个校验认证,只要你在你电脑设置过公钥,以后每次操作都不需要做任何的认证校验了。
总结就是:
HTTPS:操作简单,复制https url然后到git Bash里面直接用clone命令克隆到本地。
缺点:每次fetch和push代码都需要输入账号和密码。很麻烦!
SSH: 需要在克隆之前配置和添加好SSH。
优点:SSH默认是每次fetch和push代码都不需要输入账号和密码。
所以这里强烈推荐在你电脑上配置你的账户SSH!
我们可以在上面的弹窗中点击打开你的SSH公钥
可以看到我这里已经有了SSH公钥了,分别对应我设置过的电脑,如果你的电脑还未配置过,可以查看SSH 公钥设置
看到这里,有些小白还是不知道怎么配置,一看又是一大堆看不懂的指令,但其实就是跟着文档全部敲一遍就可以了。
在跟着敲完后,复制你电脑输出的SSH公钥(注意是你电脑的,不是文档的)
在复制完后就可以跟着继续操作添加
再在你电脑上的Windows PowerShell 或者 Git Bash输入:
ssh -T git@gitee.com
如果看到以下结果,就证明你的SSH配置成功了!
温馨提示,SSH是根据机器识别的,也就是说,如果你在公司电脑配置了,但是你在家里电脑还未配置,就要再跟着上面的操作配置一遍即可。
我们可以看到在gitee克隆下载/弹窗中,不断提示我们:为确保你提交的代码身份被 Gitee 正确识别,请执行以下命令完成配置
。
首先是为什么要配置用户名跟邮箱?其实这两个主要是用于本地修改代码后commit信息会显示修改人以及邮箱地址,也就是说这样谁写了这段BUG,在日后查找的时候一目了然!
git config --global user.name "username"
git config --global user.email "xxx@xxx"
在你输完以上两行代码后,可能发现没反应?那就是好事,没反应就是成功了!
所以你可以输入以下两行指令查看你刚才设置的用户名跟邮箱
git config user.name
git config user.email
如果你最后的指令跟上图差不多,那说明你的用户名跟邮箱已经设置成功!
但是虽然说用户名跟邮箱可以随意设置(极其不建议这样做!),最好是user.email跟你的Github邮箱或者gitee邮箱一致。
如果本地设定的user.email值与GitHub上的账户的邮件地址相同,GitHub会认定推送代码的操作是账户拥有者自己做的,跟直接登录到GitHub,从网站上修改,是相同的。此时,修改人是一样,就是账户拥有者。
如果本地设定的user.email值与GitHub不同,也能把代码推送到GitHub(只要密码或者ssh正确),GitHub会记录这次的修改是另一个人做的。
这个较为简单,就是把远程代码克隆到本地(这里使用SSH)
git clone git@你的项目地址.git
这样就可以把你远程的代码克隆到本地啦
在讲到分支时,很多初学者可能不理解分支的作用,那我就根据在实际项目中的使用场景进行不同的解释,其实分支基本算是Git的最大的作用了。
在我们创建项目的时候,会有一个默认分支:master
(生产环境),但在实际项目中,一般都需要一个dev
分支(开发环境主分支)。而分支的作用通俗一点就是,相当于把你的项目拷贝各个子目录,这些子目录相互独立。
那我们直接上场景!
实际操作1:
刚才不是在Gitee新建了仓库?但是仓库什么都没有(已把刚才那两个md文件删了,右键手动删除即可)。
进入到你本地代码目录中空白处右键打开Git Bash
,在该目录中,我就用3个文件来模拟即可。
或者出去目录外右键目录打开Git Bash
分别输入以下代码:
初始化git(相当给你的目录文件夹初始化一个git代码库)
git init
因为你已经在本地有代码文件了,所以直接 git add .
添加当前目录的所有文件到暂存区
git add .
这时候就要提交代码了,利用指令: git commit -m '第一次初始化代码'
把代码提交暂存区到本地仓库区,注意这个后面提交备注可以随意填写
git commit -m '第一次初始化代码'
做完以上命令后,你的本地git仓库已经保存完成了,这时候就得跟你刚才新建的Gitee远程仓库关联起来
git remote add origin git@gitee.com:your_username/your-code-name.git
注意后面的url就是你在用SSH克隆的url
上面的指令意思其实也很简单
git remote add
:用于添加一个新的远程仓库。
origin
:这是你给远程仓库设置的别名(通常是origin
,但也可以是其他任何你喜欢的名字)
而最后面的URL就是你远程仓库URL。做完以上这些后,就可以把代码从你的本地仓库推送到远程仓库啦!
git push -u origin master
git push
:用于将本地的更改推送到远程仓库。-u
:这个选项用于在推送的同时,将本地分支与远程分支建立上游关系。这意味着之后你可以使用更简短的命令(如git pull
而不是git pull origin master
)来拉取远程分支的更改,因为Git会记住这个上游关系。origin
:这是远程仓库的别名。master
:这是你要推送的本地分支的名称,以及你希望它在远程仓库中对应的分支名称。总结就是:把你本地分支 master
(默认分支)推送到远程的 master
分支(同样也是新建仓库时默认分支)
而使用 -u origin
就是建立上游关系,这样以后推送代码的时候,直接使用 git push
就可以啦,或者说以后拉取代码的时候直接使用 git pull
但是!有些同学可能在这里遇到了问题!例如:
别担心!这是因为我们刚才手动在Gitee那里手动删除了 README.md
这个文件,导致报错说你还没有拉取最新的更新,那我们直接按照它的提示操作:git pull
但是又出现问题了!git提示你不是在master分支上,那就按照它的提示去操作
git branch --set-upstream-to=origin/master master
执行这段指令的意思就是确立本地 master
分支与远程仓库中 origin
仓库的 master
分支之间的跟踪关系,以便在推送和拉取代码时更方便地进行同步操作。
其实如果没有刚才的演示操作,只要执行到
git push -u origin master
就完成了
这时候我们已经真正设置好了跟远程分支的连接,那就让我们再拉取一次远程分支内容!
git pull --allow-unrelated-histories
那为什么要加--allow-unrelated-histories
呢,因为本地分支跟远程分支没有共同提交的历史,加上后就允许合并历史,因为远程分支没有任何内容所以不用担心会出现冲突或者问题。
那我们再去提交一次代码!
git push -u origin master
这样就表示已经推送成功了!
那我们在远程仓库可以看到你刚才提交的代码了!
再温馨提示一次:如果没有刚才的演示操作(手动在gitee新增/删除/改动文件)就不会出现这些报错问题,所以遇到报错不要慌,基本按照Git提示就能解决!
在刚才的项目文件中,细心的同学可以发现,有.gitignore
文件的存在,而.gitignore
文件是git也是很重要的部分,主要用于忽略某些文件/目录的更改、提交等。
例如你是一个前端开发人员,你也不想你的依赖包 node_modules
提交到远程仓库吧?因为如果把依赖也提交到远程,这样一是会导致提交文件过大,会导致提交失败,以及每次改动git都会遍历node_modules
目录下的所有文件,导致效率极其缓慢。这时候我们可以通过编辑 .gitignore
文件让Git在保存提交的时候忽略某些文件/目录,达到过滤的效果。
如何在 Git 中忽略一个文件和文件夹
如果你想只忽略一个特定的文件,你需要提供该文件在项目根目录下的完整路径。
例如,如果你想忽略位于根目录下的 text.txt 文件,你可以做如下操作:
/text.txt
而如果你想忽略一个位于根目录下的 test 目录中的 text.txt 文件,你要做的是:
/test/text.txt
你也可以这样写上述内容:
test/text.txt
如果你想忽略所有具有特定名称的文件,你需要写出该文件的字面名称。
例如,如果你想忽略任何 text.txt 文件,你可以在 .gitignore 中添加以下内容:
text.txt
在这种情况下,你不需要提供特定文件的完整路径。这种模式将忽略位于项目中任何地方的具有该特定名称的所有文件。
要忽略整个目录及其所有内容,你需要包括目录的名称,并在最后加上斜线 /:
test/
这个命令将忽略位于你的项目中任何地方的名为 test 的目录(包括目录中的其他文件和其他子目录)。
需要注意的是,如果你只写一个文件的名字或者只写目录的名字而不写斜线 /,那么这个模式将同时匹配任何带有这个名字的文件或目录:
# 匹配任何名字带有 test 的文件和目录
test
如果你想忽略任何以特定单词开头的文件或目录怎么办?
例如,你想忽略所有名称以 img
开头的文件和目录。要做到这一点,你需要指定你想忽略的名称,后面跟着 * 通配符选择器,像这样:
img*
这个命令将忽略所有名字以 img 开头的文件和目录。
但是,如果你想忽略任何以特定单词结尾的文件或目录呢?
如果你想忽略所有以特定文件扩展名结尾的文件,你需要使用 * 通配符选择器,后面跟你想忽略的文件扩展名。
例如,如果你想忽略所有以 .md 文件扩展名结尾的 markdown 文件,你可以在你的 .gitignore 文件中添加以下内容:
*.md
这个模式将匹配位于项目中任何地方的以 .md 为扩展名的任何文件。
在实际前端项目中可能会忽略以下这些目录/文件(根据实际情况自行编写)
node_modules/
dist/
.vscode
在说场景之前,我们先简单了解一下不同分支的作用。在本地开发中,可能会出现不同分支从而应对不同的场景作用。
本地分支:
master
: 默认主分支,是生产环境分支,在本地开发中基本不会改动。
dev
: 默认开发分支,是开发环境分支,在本地开发中基本不会在该分支上直接改动,主要用于拉取远程最新代码,以及合并其他分支代码。
数字分支
:需求分支,开发环境分支。在实际开发中,我们需要根据不同需求去切换不同的分支,这样就能保持需求代码的独立,就算做不完这个需求也不会影响主分支的代码。有时也用于修改该需求的Bug
个人命名分支
:开发环境分支。在实际开发中,你想在这个项目做一些暂时不能影响主分支的代码测试。或者临时修改bug
hotfix
:临时紧急修复分支,正式环境分支。比如你代码已经上线了,但是临时发现了Bug,必须立马修改,该分支就起到了作用。
远程分支:
master
、 dev
、hotfix
,以及可能出现的其他分支…
下面我会根据实际场景去分析这些分支的作用。
假设我们已经有了Gitee远程仓库,用 git clone
指令克隆代码到本地后,这时候要注意,就算远程仓库存在多分支情况(master
、 dev
、hotfix
),我们克隆下来的是默认在master分支的,以及克隆下来的是代码目录。
在我们关闭Git Bash
后,重新打开就可以看到你所在分支
因为我们目前的远程分支只有master
,我们需要在本地切换到dev分支
,使用以下指令
git checkout -b dev
git checkout -b dev
是用于创建一个新的分支并切换到该分支上。让我们来解释这个命令:
git checkout
: 通常用于切换分支。-b dev
: 这是 git checkout
命令的一个选项,-b
的意思是创建并切换到一个新的分支。dev
是新分支的名称,在这里是你指定的分支名。综合起来,git checkout -b dev
的意思是:
dev
的分支,则会切换到 dev
分支。dev
的分支,则会创建一个名为 dev
的新分支,并将当前工作目录切换到这个新分支上。
相当于把 master 分支上的所有内容拷贝到 dev 分支上,但相互独立,这样你就可以在dev分支上进行一些代码操作(不建议直接修改dev分支)
那我们的个人分支呢?例如用你的名字缩写(这里用cpc为例),那我们可以继续创建一个 cpc
分支并切换到该分支。
git checkout -b cpc
值得注意的是,你从哪个分支上开始创建分支的,它就把你那个分支上的内容拷贝一份并切换到你新建的分支。所以刚才的操作相当于:把dev上的所有内容拷贝到新的cpc分支,这时候cpc分支的内容跟dev内容是一样的!
好,这时候我们已经创建好属于你自己的个人本地分支,注意是本地。这时候我们可以随意修改代码了,例如修改 README.md
文件
在你修改完并保存后,就想推送到远程仓库,刚才我们提到,一般来说远程仓库为了方便管理,只会存在一些重要分支(master
、 dev
、hotfix
以及其他分支),那我们现在远程还没有dev分支,就让我们来创建一个吧~
在你的cpc分支上更改完代码后,就需要保存并提交到你的本地Git仓库,
git add .
git commit -m '修改了md文件'
可以看到在输入完 git commit -m '修改了md文件'
后,Git输出了: 1 file changed
,这是因为我们刚才只修改了一个文件也就是md文件。做完以上操作后我们就完成了:暂存所有文件并提交到了本地的cpc分支仓库。
因为dev分支是我们生产环境的主分支,所以我们在更改代码后就需要把这些代码合并到dev分支并提交到远程仓库
因为已经在cpc分支上提交到了本地仓库,我们就可以切换到本地的dev分支(记住一定要先暂存提交!)
git checkout dev
有些同学可能疑问,为什么这时候不需要加-b
了呢,这是因为-b是新建分支,但是我们本地刚才已经创建过了dev分支,直接切换即可
可以看到我们正常切换到了dev分支,同时打开文件,可以看到dev分支的内容还是原来的。
那我们可以使用 git merge cpc
指令把cpc分支修改的内容合并到dev分支
git merge cpc
如果出现以上输出,说明已经合并成功,并提示哪个文件做了修改。那我们再去看一下文件:
合并成功! 说明你已经成功把cpc修改的内容合并到了dev分支。
既然我们已经把代码改完并合并到本地的dev分支了,我们就要把dev分支上的内容提交到远程仓库。这样其他成员使用的时候就会能看到最新的代码。
我们使用 git push
去推送代码
git push
出错了! 但是别慌,这是因为我们远程仓库并没有dev分支
,那我们设置一下关联不就好了
要解决这个问题,可以按照提示的建议执行以下命令:
git push --set-upstream origin dev
这条命令的含义是:
git push
: 尝试将当前分支的更改推送到远程仓库。--set-upstream origin dev
: 设置当前分支 dev
的远程跟踪分支为 origin/dev
,这样之后执行 git push
或 git pull
时就不需要再指定远程分支了。执行这条命令后,Git 将会将本地的 dev
分支与远程仓库的 dev
分支关联起来,之后可以直接使用 git push
和 git pull
命令,Git 将自动使用正确的远程分支进行操作。
OK,推送成功! 我们再去Gitee上看看:
我们已经成功创建了远程分支。那我们再去看看dev分支下找到md文件,可以看到我们修改的内容! 这样远程仓库的dev分支就有了最新的代码!
那如果我远程仓库已经有dev分支了怎么办?
好,现在假设我们要重新克隆该项目,克隆完并关掉 Git Bash 窗口
并再次打开
重新打开后,可以看到我们默认是在master,因为远程已经有了dev
分支,我们直接用 git checkout dev
切换到dev
分支即可。
假如某天领导给开发AAA跟开发BBB分别布置了一些需求任务,正常操作流程应该是:根据需求编号(例如001、002)去创建本地分支。
假设开发AAA今天要做001需求,那他就得从dev
分支拉取最新代码,然后新建分支并切换到新分支,这里要注意的是从dev
分支切换,这是因为需要先拉取最新代码,并把dev
分支代码拷贝到001
分支。这样到时候改完合并代码时能大大减少冲突概率。
前置条件:如果处于非dev分支,例如在刚才的个人分支cpc分支,并做了代码修改怎么办?
这是初学者可能会经常遇到的问题,突然领导给你加了一个需求或新出现一个bug,但是你已经在个人分支
或其他分支
上做了代码修改操作。那这时候该怎么办呢?
那就需要先暂存到当前本地分支,再切换到dev分支,注意!这里只是切换不是合并,相当于你保存了cpc分支,等有空了再回来完善,临时切换到dev分支,两个分支相互独立!
git stash
具体来说,git stash
的作用是:
在保存完当前分支后,我们就可以正常切换回dev
分支了
如果你没有上述的前置条件,本身就处于在dev分支,那就直接拉取最新代码并新建分支即可
git pull
git checkout -b 001
可以看到我们已经处于最新代码的001分支,这时候我们就可以去完成001需求啦
代码冲突主要是出现在代码合并阶段,那我们来思考一下以下三种情况哪种会发生冲突?
- 两个人对同一项目的不同文件进行了修改
- 两个人对同一项目的同一文件的不同区域进行了修改
- 对同一项目的同一文件的同一区域进行了不同修改
答案就是:第三种!前面两种Git会自动帮我们合并代码,而第三种是需要我们手动去合并
问题1:什么是自动合并呢?
合并本质上可以理解为将两个人(分支)对项目的修改整合到一块,注意是对项目的修改。上述三种情况的前两种是两个人对项目的不同区域进行修改,互不干扰,所以Git可以自动的将两个人对项目的修改整合到一起
问题2:什么是手动合并呢?
当Git不知道该保留两个修改中的哪一个时,就需要手动来进行这个决策,可以选择保留两个修改中的任意一个,或是选择将两个修改全部保留。完成上述决策就是手动合并的目的。
问题3:为什么需要手动合并?
当可以自动合并时,说明两个人的修改不会冲突,但是当两个人对同一文件的同一区域进行了修改那么这两个修改就会产生冲突,Git将无法整合这两个修改,因为Git不知道它该保留两个修改中的哪一个(或是要一并保存),这是就需要人工进行手动合并了。
dev
分支,这时你在001
分支已经写完了需求,并进行了git add .
跟 git commit -m '修改A文件'
,现在切换回dev
分支,然后执行了一次git pull
,发现有更新,这时候你需要把001
分支内容合并到dev
,你开始操作:git merge 001
,发现报错了!# 处于001分支
git add .
git commit -m '修改了A文件'
# 切换回dev分支
git checkout dev
# 拉取最新更新
git pull
# 把001分支内容合并到dev
git merge 001
借用网上的图进行展示
出现类似以下信息说明 _config.yml
文件有冲突。这时候就可以打开_config.yml
打开文件我们可以看到冲突的内容,例如:
<<<<<<<HEAD hello world 001 ======= hello world dev >>>>>> dev
关于怎么手动解决只需要手动点击选择即可,在解决完所有的文件冲突后,我们可以进行保存文件并提交到远程仓库。
git add .
git commit -m "合并了_config.yml文件"
git push
这时候我们就可以成功解决了合并冲突!
实际开发中,可能常常遇到bug以及临时需求,你可能专注于某些代码中,已经做了很深度的修改,这时候领导让你要紧急处理这个问题。其实跟我们刚才场景3的前置条件一样。所以我一直强调的是,不要直接在master/dev分支
上直接操作代码,保证这两个主分支的干净历史。
所以我们无论是测试代码,还是新需求,又或者修改bug,都需要切到单独分支上去操作。
测试代码:
可以切换到你的个人分支(例如cpc分支上),又或者从dev分支新建一个单独测试分支。
新需求: 可以以需求编号为分支名,从dev分支上新建单独数字分支
修改bug: 如果是独立bug,需要从dev分支上新建bug分支进行修改,修改完再合并到dev
如果是临时处理问题,则需要像前置条件流程一样处理,需要先暂存到当前本地分支,再切换到dev分支,注意!这里只是切换不是合并,等有空了再回来完善,临时切换到dev分支,两个分支相互独立!
git stash
git pull
git checkout -b 新分支
细心的同学可以注意到,我在创建新分支之前都会
git pull
一次,这是为了确保dev分支上的代码是最新状态
。同时注意的是,你可能在完成你的需求同时别人已经提交了代码到远程仓库了,所以dev分支在合并其他分支之前也要进行一次git pull
前面我们已经提到master的作用主要是用于生产环境(部分公司为了省事可能直接使用dev分支做正式环境代码,反正是两套服务)。那我们就需要把dev分支上的代码合并到master分支,并推送到远程。
# 在dev分支上拉取最新的远程dev代码
git pull
# 切换到master分支
git checkout master
# 拉取最新master代码
git pull
# 合并dev
git merge dev
# 推送到远程master
git push
在该过程中一般合并代码不会出现冲突,如果出现按照上面的解决方法解决即可,这时候我们就能确保远程的master分支的代码是全新的了。、
当然还有一个更省事的办法就是直接使用dev分支的代码。只要正确使用是不会出现问题的。
这可能是会出现的问题,而这时候就要一个 hotfix
热修复分支,主要是操作步骤:
切换到master分支并拉取最新代码
git checkout master
git pull
需要从master新建一个热修复分支并加以版本号,如:v-1.0.0-hotfix
,常用于快速修复生产环境中的紧急 bug 或问题,其主要作用是在不影响正在开发的主分支或其他功能分支的情况下,快速地修复生产环境中的问题。
# 新建并切换到热修复分支
git checkout -b v-1.0.0-hotfix
在v-1.0.0-hotfix
分支上修复完bug后,需要合并到线上分支master
,并推送
# 假设已经修复完bug
git add .
git commit -m '临时修复bug:v-1.0.0'
# 切换回master分支
git checkout master
# 合并热修复分支的内容
git merge v-1.0.0-hotfix
# 推送到master远程分支
git push
这样就能进行临时修复了,但是也要注意把临时修复的内容合并到dev分支
# 切换回dev分支
git checkout dev
# 合并热修复分支的内容
git merge v-1.0.0-hotfix
# 推送到dev远程分支
git push
如果出现合并冲突,同样的解决方法即可。(以上版本号可根据实际情况自定)
看到这里,其实上面7种场景基本上能覆盖实际项目开发中的各种情况,可以看到用到最多的其实就是那几个指令:
# 暂存所有文件
git add .
# 提交修改到本地仓库
git commit -m 'xxx'
# 暂存所有文件到仓库,方便后续继续修改
git stash
# 切换到指定分支
git checkout <branch>
# 拉取更新
git pull
# 推送代码
git push
这些指令作用也做了详细说明,包括出现的一些特殊情况的应对方法。
那再介绍几个可能会常用到的指令
# 列出所有本地分支 git branch # 列出所有远程分支 git branch -r # 列出所有本地分支和远程分支 git branch -a # 放弃当前分支所有修改 git checkout . # 删除分支 git branch -d [branch-name] # 删除远程分支 git push origin --delete [branch-name] git branch -dr [remote/branch]
关于代码回退等指令,这里就不做过多说明了,因为我个人觉得不太适合初学者,如果非要去找相关的提交历史,其实可以通过gitee可视化去操作。
以上教程基本上是针对Git初学者,结合例子的同时讲解理论方便理解,如有不对的地方请各位大佬轻喷。有任何问题可随时交流~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。