前言
Git 是Linus使用C语言开发的最先进的分布式版本控制系统,本次笔记的目的在于学会Git技术原理会熟练使用Git、github、gitlab进行实际开发 ’。
在Windows上安装Git
安装完成后,还需要最后一步设置,在命令行输入:
配置邮箱
$ git config --global user.name "Your Name" $ git config --global user.email "email@example.com"
注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。
Git基础常用控制台命令
git init
选择一个系统目录打开git bash 客户端的窗口输入一下命令:
$ git init
git add
第一步,用命令 git add 告诉Git,把文件添加到仓库:
$ git add readme.txt $ git add file2.txt file3.txt
第二步,用命令 git commit 告诉Git,把文件提交到仓库:
$ git commit -m "wrote a readme file" $ git commit -m "add 3 files."
git status
git status 命令可以让我们时刻掌握仓库当前的状态
git diff
git diff 顾名思义就是查看difference,用于查看上次提交都做了那些改动。
git log & git log --pretty=online
git log 命令显示从最近到最远的提交日志。我们可以根据最近提交的日志进行选择性的回滚到自己想要的版本。
在后面加上--pretty=online 可以格式化显示为一行内容。
git reset head^
在Git中,用HEAD表示当前版本,也就是最新的提交版本。git reset可以把当前版本进行一个回退切换。
$ git reset --hard 1094a HEAD is now at 83b0afe append GPL
工作区 && 暂存区 &&版本库
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
当我们在工作区开发好代码后,一般先将代码提交到git的暂存区,然后进行 git commit 命令提交到分支上。
git checkout
撤销修改 -- gitcheckout 可以把工作区的内容撤销到最近的一次 git commit 的状态或者git add的状态。
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令。
远程仓库
GitHub
第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
踩坑:在windows中直接输入 ssh-keygen -t rsa -C “your email”后 显示已经生成key但是默认目录下找不到对于的秘钥文件,故而 查找解决方法如下:
ssh-keygen -o
使用以上命令即可解决问题,就可以查找 到公钥文件,绑定到github账号上
命令执行成功就会在默认的用户目录下生成密钥&公钥文件id_rsa和id_rsa.pub
两个文件其中id_rsa.pub是公钥可以放心的告诉任何人。
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。也就可以解决你可以从多个电脑上提交你的代码到远程仓库。
添加远程仓库
登录github官网,进行创建远程仓库如下图:
gitHub创建成功后的友情提示如下:
git init git add readme.md git commit -m "first commit" git branch -M main //新建一个分支 git remote add origin xxxxx.git git push -u origin mian //第一次加上-u参数 推送到你需要推送的分支上即可
接下来关联远程库与本地库:
$ git remote add origin git@github.com:michaelliao/learngit.git
添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
下一步,就可以把本地库的所有内容推送到远程库上:
由于远程库是空的,我们第一次推送master分支时,加上了-u参数
git clone xxxx.git
经常推荐的使用方法是 先在远程库建立仓库,然后本地去克隆一个仓库到本地进行开发,然后再关联远程库进行推送。
分支管理
目的和意义:
假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
创建与合并分支
创建dev分支,然后切换到dev分支:
$ git checkout -b dev Switched to a new branch 'dev'
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev $ git checkout dev Switched to branch 'dev'
git branch
查看当前分支
$ git branch * dev master
当我们在创建的dev分支上进行开发后可以正常的提交修改。但是当我们开发完成后就需要进行合并到master分支去,然后删除dev分支的内容。
git merge
git merge dev 表示合并分支到新建的当前分支中去,这样的话当前分支就和dev分支内容一致了,然后就可以删除掉dev分支了。
$ git branch -d dev Deleted branch dev (was b17d20e)
switch
我们注意到切换分支使用git checkout <branch>,而前面讲过的撤销修改则是git checkout -- <file>,同一个命令,有两种作用,确实有点令人迷惑。
实际上,切换分支这个动作,用switch更科学。因此,最新版本的Git提供了新的git switch命令来切换分支:
创建并切换到新的dev分支,可以使用:
$ git switch -c dev
直接切换到已有的master分支,可以使用:
$ git switch master
使用新的git switch命令,比git checkout要更容易理解。
解决冲突
冲突出现的原因:两个不同的分支对同一个文件的同一行文件 进行修改然后添加到暂存区后进行,提交合并分支,就会出现冲突的情况。
我们可以直接查看readme.txt的内容:
Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEADCreating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再次提交就可以解决冲突了,冲突的主要修改就是需要开发者决定需要以那个分支的代码为准,然后再进行提交。
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph命令可以看到分支合并图。
分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
我们在平时开发中先使用 git switch -v dev 创建一个分支,然后在分支上进行我们的日常开发,然后提交代码到远程仓库去,然后我使用 git switch master 切换回主干分支上准备进行代码合并。
禁言默认的 fast forward 的方式进行 合并,有个很大的好处就是 ,当我们删除掉dev分支后,使用 git log --graph 查看提交日志的时候 能很清楚地看到合并代码的痕迹,方便以后查看。
git merge --no-ff -m "合并提交" dev //-m必须加 ,当做一次新的提交
Bug分支
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场;
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
git stash 保存当前的dev分支 现场 git checkout master //切换回master分支 准备修复bug git checkout -b issue-101//先建bug分支 //修复bug 并提交 $ git add readme.txt $ git commit -m "fix bug 101" //现在,是时候接着回到dev分支干活了! $ git switch dev //工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法: 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;另一种方式是用git stash pop,恢复的同时把stash内容也删了:
在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。同样的bug,要在dev上修复,我们只需要把(修复bug的提交 )4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来。
$ git cherry-pick 4c805e2
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场;
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
Feature分支
开发一个新feature,最好新建一个分支;
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。
多人协作
-
查看远程库信息,使用git remote -v;
-
本地新建的分支如果不推送到远程,对其他人就是不可见的;
-
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
-
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
-
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
-
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
Rebase
-
rebase操作可以把本地未push的分叉提交历史整理成直线;
-
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。