本文由云+社区发表作者:工程师小熊摘要:用了很久的Git和svn,由于总是眼高手低,没能静下心来写这些程序员日常开发最常用的知识点。现在准备开一个专题,专门来总结一下版本控制工具,让我们从git开始。完成本系列博客的阅读以后,你将掌握git的基本概念与git的基本命令,可以在本地随心所欲的完成代码的提交撤销保存修改等操作、可以流畅的参与多人协作,本文致力于快速的入门,如果涉及到更高级的功能需要进行更深一步的学习。本文核心点:Git的基本概念一个人使用Git时的代码版本控制–(提交、拉代码、分支操作)多人合作时的代码版本控制–(合并冲突、暂存代码)什么是Git简介git是世界上目前最先进的分布式版本控制系统,致力于团队、个人进行项目版本管理,完美的解决难以比较代码、难以合并代码、难以取消修改、难以在写当前代码的过程中保存未完成的修改去修改线上版本的bug等的痛点。git是一个非常强大的工具,但作为一个git使用者来说,不用完全学习Git的知识点与命令,因为有的命令的使用频率非常的低甚至数年都不会用到,让我们来由浅入深进行学习。git的历史git是linux的创始人linus,在付费版本控制工具BitMover收回对Linux社区免费使用权利的时候,一怒之下花费两个星期的时间写出来的。(牛笔的人)开始安装git选择自己的操作系统对应的git版本安装,安装成功后运行git version后,输出git版本则安装正确。git 官方: https://git-scm.com/downloads配置用户信息使用git config命令来配置用户名和邮箱git config –global user.name “pzqu” git config –global user.email pzqu@example.com如果用了 –global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 –global选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。使用git config user.name和git config user.email来检查是否成功,也可以直接用git config –list来列出全部git配置信息来查看创建git托管的项目假如我们创建一个项目叫make_money,先创建一个文件夹叫make_money,再使用git init命令创建git项目。# pzqu @ pzqu-pc in ~/Documents/code/test [0:05:29]$ mkdir make_money# pzqu @ pzqu-pc in ~/Documents/code/test [0:06:24]$ lsmake_money# pzqu @ pzqu-pc in ~/Documents/code/test [0:06:29]$ cd make_money# pzqu @ pzqu-pc in ~/Documents/code/test/make_money [0:07:10]$ git initInitialized empty Git repository in /Users/pzqu/Documents/code/test/make_money/.git/# pzqu @ pzqu-pc in ~/Documents/code/test/make_money on git:master o [0:07:12]$ ls -altotal 0drwxr-xr-x 3 pzqu staff 96 11 7 00:07 .drwxr-xr-x 3 pzqu staff 96 11 7 00:06 ..drwxr-xr-x 9 pzqu staff 288 11 7 00:07 .git创建成功以后,会出现一个叫.git的隐藏文件夹,这个就是你的git仓库,以后所有的git操作历史提交记录信息就全部记录在此了,只要这个文件夹在就可以记住我们的全部git操作工作区和暂存区在使用git的时候还要清楚暂存区和工作区的含义,参考廖雪峰的官方网站-git篇-工作区和暂存区常见情况提交代码新文件与修改# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [11:37:50]$ lsREADME.md# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [11:42:02]$ touch file1.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [11:42:15]$ git add file1.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [11:42:23]$ git statusOn branch masterYour branch is up to date with ‘origin/master’.Changes to be committed: (use “git reset HEAD <file>…” to unstage) new file: file1.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [11:56:38]$ git commit -m “[+]add new file1.txt”[master 66cc488] [+]add new file1.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file1.txt上图操作包含:创建新文件file1.txtadd 添加修改的内容到索引status 查看修改的内容commit 把索引提交到本地分支git add . :监控工作区的状态树,此命令会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件。git add -u:他仅监控已经被add的文件(即tracked file),他会将被修改的文件提交到暂存区。add -u 不会提交新文件(untracked file)。(git add –update的缩写)git add -A :是上面两个功能的合集(git add –all的缩写)upload successfulgit show 列出最近一次的提交对于commit:像这样,你不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。删除文件# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [12:55:24]$ lsREADME.md file1.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [12:55:25]$ git rm file1.txtrm ‘file1.txt’# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [12:55:30]$ lsREADME.md# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [12:55:32]$ git statusOn branch masterYour branch is ahead of ‘origin/master’ by 1 commit. (use “git push” to publish your local commits)Changes to be committed: (use “git reset HEAD <file>…” to unstage) deleted: file1.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master x [12:55:40] C:128$ git commit -m “[-]delete file1.txt”[master e278392] [-]delete file1.txt 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 file1.txt上图操作包含:创建新文件file1.txtgit rm 删除file1.txt文件status 查看修改的内容commit 把索引提交到本地分支tip1: 如果没有用git rm删除文件,在本地删除文件后,git add一下再提交可以达到同样的效果tip2: 要是你加班太晚,头晕不小心删除了不想删除的文件怎么办?见下一篇:版本控制工具——Git常用操作(下)-后悔药拉代码方法一 pull# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [17:01:13]$ git pullremote: Enumerating objects: 4, done.remote: Counting objects: 100% (4/4), done.remote: Compressing objects: 100% (2/2), done.remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0Unpacking objects: 100% (3/3), done.From github.com:pzqu/git_test 5fd4d8f..7b54a8a master -> origin/masterMerge made by the ‘recursive’ strategy. share_file.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 share_file.txt上图命令:git pull查看本地仓库变化git logupload successful上图可以看到向远程仓库pull的时候,出现了两个新的commit,commit 7b54a8ae74…的提交信息为Create share_file.txt,另一个commit fdbb19cf4c51770的提交信息为Merge branch ‘master’ of github.com:pzqu/git_test。事实上主线只有一个提交,为什么会出现这种情况? 是因为pull其实会做两个操作拉远程仓库代码到本地自动与当前分支合并并生成一个合并成功的提交注意这里的第二个个步骤如果远程有人和你改了同一个文件就会出现一个冲突,这个时候git会提示你哪些文件有冲突,手动改了再提交一次就可以了。详情见合并冲突方法二 fetch我在远程修改了文件,向share_file.txt加了一行内容tom modify,此时拉代码。# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [21:07:21]$ git fetch# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:master o [21:08:43]$ git rebase origin/masterFirst, rewinding head to replay your work on top of it…Applying: [+]add new file1.txtApplying: [-]delete file1.txt上图所示有以下两个操作fetch 拉取远端代码到本地rebase 把本地代码提交基于远端分支重新replay效果如下:upload successful上图是git log所输出的提交内容,刚刚pull的时候忘记把pull自动产生的merge提交到远程,rebase的时候把本地的提交放到了远程提交之后,看起来就是一条直线,比较优雅,也是推荐的方式。同样的,如果产生了冲突,详情见合并冲突分支操作创建分支分支是多人协同最经典的地方所在,我们来创建一个分支$ git checkout -b dev/pzqu origin/masterBranch ‘dev/pzqu’ set up to track remote branch ‘master’ from ‘origin’.Switched to a new branch ‘dev/pzqu’$ git branch* dev/pzqu mastergit checkout -b 分支名 其他分支,-b代表创建并切换到新建的分支,分支名代表新创建的分支叫什么名字,这里叫dev/pzqu ,其他分支代表基于哪一个分支来创建,这里基于远程的master分支origin/master,如果省略则代表基于当前分支git branch展示本地的分支情况,加-a参数可以展示全部的分支,包括远程分支在分支前,指明了现在所在的分支是dev/pzqu切换分支$ git checkout -b dev/pzqu2Switched to a new branch ‘dev/pzqu2’$ git branch dev/pzqu dev/pzqu2 master$ git checkout dev/pzquSwitched to branch ‘dev/pzqu’Your branch is up to date with ‘origin/master’.$ git branch* dev/pzqu dev/pzqu2 master基于当前分支创建了一个新的分支并自动切换过去dev/pzqu2git checkout 已存在的分支名切换分支回到dev/pzqu删除分支$ git branch* dev/pzqu dev/pzqu2 master $ git branch -D dev/pzqu2Deleted branch dev/pzqu2 (was 7c9be37).$ git branch* dev/pzqu master 位于dev/pzqu,删除了dev/pzqu2分支合并冲突合并同一个分支的冲突(常见)为了产生一个冲突,我在另一个地方向远程仓库提交了代码,更改share_file.txt文件,加了一行内容tom add for merge,本地修改同一个文件加了一行pzqu add for merge,并提交到本地,这样一来,本地和远程仓库的同一个文件就不一样了,一会拉代码一定会产生一个冲突。效果如下:upload successful一般rebase或pull冲突的时候,都会出现提示,然后git status会出现上图图示这个时候不可以进行任何分支切换和commit操作,按照他提示进行处理git status提示哪个文件是都被修改的,both modified,然后使用编辑器修改该文件,解决冲突解决完成后,git add 添加该冲突文件git rebase –continue,并更新commit message,完成整个rebase流程 我们来看看这个冲突的文件:upload successfulGit用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:upload successfulgit add再git rebase –continue后完成rebase,效果如下,再push的远程仓库即可upload successful合并不同分支的代码产生冲突关于怎么创建分支与切换分支见创建分支和切换分支,这里只讨论合并时产生的冲突的情况,我们已经基于master分支创建了一个dev/pzqu分支$ git branch* dev/pzqu master切换到master分支,加一行master add for merge并提交,文件内容如下:$ cat share_file.txttom addtom modifytom add for mergepzqu add for mergemaster add for merge切换到dev/pzqu分支,向share_file.txt加入一行dev/pzqu add for merge并提交,现在share_file.txt内容如下:$ cat share_file.txttom addtom modifytom add for mergepzqu add for mergedev/pzqu add for merge现在两个分支的同一个文件内容不一样了,现在我们在dev/pzqu分支上进行合并:$ git merge masterAuto-merging share_file.txtCONFLICT (content): Merge conflict in share_file.txtAutomatic merge failed; fix conflicts and then commit the result.# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:dev/pzqu x [11:17:31] C:1$ git statusOn branch dev/pzquYour branch is ahead of ‘origin/master’ by 1 commit. (use “git push” to publish your local commits)You have unmerged paths. (fix conflicts and run “git commit”) (use “git merge –abort” to abort the merge)Unmerged paths: (use “git add <file>…” to mark resolution) both modified: share_file.txtno changes added to commit (use “git add” and/or “git commit -a”)$ cat share_file.txttom addtom modifytom add for mergepzqu add for merge<<<<<<< HEADdev/pzqu add for merge=======master add for merge>>>>>>> master上图出现了一个冲突,是我们意料之中的,修改share_file.txt文件,解决此冲突:$ cat share_file.txttom addtom modifytom add for mergepzqu add for mergedev/pzqu add for mergemaster add for merge$ git add share_file.txt# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:dev/pzqu x [11:22:40]$ git commit -m “[]merge master to dev/pzqu”[dev/pzqu d9e018e] []merge master to dev/pzqu# pzqu @ pzqu-pc in ~/Documents/code/test/git_test on git:dev/pzqu o [11:23:00]$ git statusOn branch dev/pzquYour branch is ahead of ‘origin/master’ by 3 commits. (use “git push” to publish your local commits)nothing to commit, working tree clean冲突解决也提交了,看看我们现在的分支内容:upload successful上图我们可以看到:master分支比远程origin/master分支多一次提交,dev/pzqu分支由于是基于origin/master分支,合并了master分支的提交和当前dev/pzqu分支的提交,超出本地master两个提交,致此我们把master合并到dev/pzqu的操作就完成了。通常我们开一个新的开发分支是为了在自己的分支上写代码,方便提交也不会把主线弄乱,现在我们用同样的方法将dev/pzqu合并到master分支,然后把两个分支都提交到远程。$ git checkout masterSwitched to branch ‘master’Your branch is ahead of ‘origin/master’ by 1 commit. (use “git push” to publish your local commits)$ git merge dev/pzquUpdating 58f047a..d9e018eFast-forward share_file.txt | 1 + 1 file changed, 1 insertion(+)$ git push origin masterTotal 0 (delta 0), reused 0 (delta 0)To github.com:pzqu/git_test.git 7c9be37..d9e018e master -> master $ git push origin dev/pzquCounting objects: 9, done.Delta compression using up to 8 threads.Compressing objects: 100% (9/9), done.Writing objects: 100% (9/9), 887 bytes | 887.00 KiB/s, done.Total 9 (delta 2), reused 0 (delta 0)remote: Resolving deltas: 100% (2/2), done.remote:remote: Create a pull request for ‘dev/pzqu’ on GitHub by visiting:remote: https://github.com/pzqu/git_test/pull/new/dev/pzquremote:To github.com:pzqu/git_test.git * [new branch] dev/pzqu -> dev/pzqu切换到master分支合并dev/pzqu到master分支master推到远程仓库如果dev/pzqu要保留,就可以推送到远程仓库。upload successful现在我们可以看到全部的分支都在一起了,强迫症都舒服了。暂存代码保存现场这种情况一般是出现在你正在完成一个功能,但是忽然线上发现了一个Bug,必须马上开一个新的分支来修复bug,但是现在的功能没写完不打算提交(commit),现在怎么办??不用怕暂存代码来帮助你。$ git statusOn branch dev/pzquYour branch is up to date with ‘origin/master’.Changes to be committed: (use “git reset HEAD <file>…” to unstage) new file: need_stash.txt modified: share_file.txt$ git stashSaved working directory and index state WIP on dev/pzqu: d9e018e []merge master to dev/pzqu$ git stash liststash@{0}: WIP on dev/pzqu: d9e018e []merge master to dev/pzqu$ git statusOn branch dev/pzquYour branch is up to date with ‘origin/master’.nothing to commit, working tree clean//省略操作:去创建一个Bug分支,修复他并完成与主线的合并,删除Bug分支。//省略操作:切回来当前分支继续开发//下面来恢复现场$ git stash apply stash@{0}On branch dev/pzquYour branch is up to date with ‘origin/master’.Changes to be committed: (use “git reset HEAD <file>…” to unstage) new file: need_stash.txtChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: share_file.txtstatus查看到有2个文件修改没有提交stash把修改放到暂存区,并生成一个idstash list列出暂存区所有内容stash apply重新把暂存区内容放到本地这里的stash apply成功的把暂存区的一次暂存恢复到了本地,但是暂存区还有会保存这次暂存,如果想删除这次暂存要用git stash drop来删除;也可以用git stash pop,恢复最后一次暂存的同时把stash内容也删了。$ git stash drop stash@{0}Dropped stash@{0} (bfdc065df8adc44c8b69fa6826e75c5991e6cad0)$ git stash list好了,暂存区清干净了。 注意:要放到暂存区的文件一定要先通过git add加到index小结本文阅读结束以后,我们学会了Git的基本概念,知道git的作用、历史;学会安装配置Git,使用Git创建项目托管以及工作区和暂存区的概念学会Git的本地操作,提交、拉代码、创建切换删除分支操作,多人合作时的代码版本控制,学会了不同情况下的合并冲突、暂存代码操作下集预告Git常用操作(下)我计划给大家介绍以下点:后悔药-各种后悔操作(撤消commit,回滚,回退远程仓库等)哎呀,提交的时候漏了文件tag操作git忽略不想提交的文件注意事项理论上,git日常用到的命令是 diff show fetch rebase pull push checkout commit status 等,这些命令都不会导致代码丢失,假如害怕代码丢失,可以预先commit一次,再进行修改,但切记不可使用自己不熟悉的命令 任何命令,不要加上-f的强制参数,否则可能导致代码丢失建议多使用命令行,不要使用图形界面操作引用git官网廖雪峰的官方网站-git篇hexo博客部署到vps此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号