假设你的老板要你设计一个文档,当你设计好了,拿给他看时,他并不是很满意,就要你拿回去修改,你修改完后,再给他看时,他还是不满意,经过多次修改,他觉得还是你之前的第三次修改后的文档好,最终决定采用第三次修改后的文档,但因为前面你都是在一个文档上修改的,意味着前面修改的文档内容都被覆盖了,也就无法完成老板的任务
同上,吸取了之前的教训后,你明白了要保存前面的副本,因为老板可能会采纳之前的文档,所以每一次修改,你都存一份副本,这样,就能在最终选用文档时,拿出成果。
同上,上面的想法听起来确实很合理,一般情况下,也能解决问题,但是,在软件开发中,随着版本的不断增多,维护好版本是很有挑战的,那就需要我们知道每个版本各自修改的内容,才能更好地维护,而上面的生成副本的方式无法知晓当前版本在上一个版本的基础上修改了哪些内容(内容很多的情形),这种方式也就不适用了!此时,git应运而生!!!
git,是一个版本控制器,它是记录每次的修改以及版本迭代的一个管理系统,比如在文本文件的某一行前面添加了一行内容,也能清楚的找出这种修改。
创建本地仓库
仓库本质上就是进行版本控制的一个文件目录,用git init命令创建,下图中的.git是用来跟踪管理仓库的
配置git
用下面两个两个命令可以配置用户名和邮箱地址,这点很重要!!!其中的global表示全局,即带了这个选项,在所有仓库中都会使用你配置的这个用户名和邮箱地址,不带,则只在当前仓库有效
注意:命令必须在仓库内执行!!!
git config [–global] user.name “Your Name”
git config [–global] user.email “[email protected]”
查看配置
用git config -l命令查看配置信息
删除配置信息
git config [–global] --unset user.name
git config [–global] --unset user.email
认识工作区、暂存区、版本库
git关注的是修改,即增加、更新、修改,而修改的工作区内容会写入对象库的一个新的git对象中,文件要被git跟踪管理,就必须得进行add和commit操作,完成这两步后,文件才会被添加到仓库管理
add操作
git add 文件(文件名)/目录(目录名)/所有文件(.)
commit操作
git commit -m 日志信息,即提交暂存区的所有文件
commit后,可以用git log来查看提交的日志信息
如下图,是提交工作区的内容到版本库的示例流程,如果没有配置用户名和邮箱信息,就无法commit,会提示要你配置,配置完成后,再commit就可以了,而日志中的黄色的那一长串字符串,则是commit id
如果想看简单一些的日志,可以带–pretty=oneline选项
如下图,index就是暂存区,add后的内容都是添加到这里的
objects,保存了git维护的所有修改
如下图,查看object时,它由两部分构成,前两位是文件夹名称,后面的38位则是文件名称
用git cat-file -p commit id查看版本库对象的内容
修改文件
如下图,用git status查看工作区中状态,显示还没有添加和提交
三天前修改的文件,到今天,我们可能就已经不记得修改了哪些内容,此时就可以用到git diff来查看修改了哪些内容。a 和 b表示从之前的a文件,修改后变成了b文件,相当于同一个文件的不同版本,-1表示改动前第一行,+1,2表示改动后第一行起连续两行的内容
版本回退
如果你发现之前做的工作,出现了一些问题,需要解决,就得回到某一个历史版本,这时,就能用到git reset [–soft || --mixed || --hard] [HEAD]
HEAD,表示当前版本
HEAD^,表示上一个版本
HEAD^^,表示上上一个版本
也能直接使用commit id,表示回退到指定版本
mixed,表示回退到某个历史版本的暂存区,版本库也变了,但工作区不变,且这是个默认选项,即不指定时,就是mixed
soft,表示回退到某个历史版本的版本库,工作区和暂存区不变
hard,表示回退到某个历史版本的工作区,暂存区和版本库都变,慎重使用这个选项,因为是回退工作区,可能内容就找不回来了
以hard为例,进行讲解
如下图,从version3回退到version2了,工作区文件的内容也回退了
假如我突然后悔了,想回到version3版本,但发现根本做不到,因为我们没有version3的commit id,此时,只能借助git reflog命令来尝试补救了
如下图,我们借助git reflog命令找到了version3的部分commit id,但也能代表目标版本!!!
撤销修改
当我们觉得当前写的代码太糟糕了,想恢复到上一个版本,这时就需要用到类似于word等工具的撤销功能,分为三种情形
没有add,可以直接用git checkout – 文件名进行撤销
已经add,但没有commit,可以使用git reset HEAD 文件名,将add的回退到工作区,然后再用如上的方式撤销
已经add,已经commit,则能采用git reset --hard HEAD^,前提是你没有push到远程仓库
删除文件
用git rm命令,可以删除工作区和暂存区中的内容,然后再commit提交即可
假设你能创建自己的分身,那你就可以让自己的分身去做与自己不同的事情,比如它去学习Java,而你学习C++,在某个时间点,你们俩合并,此时,你就能既学会了Java,也学会了C++,极大地提高了你的学习效率。分支便是如此,便于团队协作,提高工作效率!!!
创建分支
用git branch来查看分支,git branch 分支名来创建分支,* 在哪儿表示HEAD指针当前指向哪一个分支,最后的cat,证明两个分支指向同一个提交
如下图,也可以用git checkout -b 分支名命令来创建并切换分支
切换分支
用git checkout 分支名来切换分支
如下图,在dev分支上创建了ReadMe文件,并写入hello world,但在master分支上却看不到,这是因为创建新分支后,master分支和dev分支是相互独立的,就如同,你并不知道你的分身干了什么事情!要想知道,就必须得将dev合并到master上
合并分支
用git merge 要合并到当前分支的分支名,fast-forward代表快进模式,也就是直接把master指向dev的当前提交
删除dev分支
当合并完成后,dev分支也就没用了,如下图,用git branch -d 分支名来删除分支,注意,不能在当前分支下删除当前分支!!!
如果dev分支没有被合并
可以用git branch -D 命令来删除dev分支
合并冲突
分支在合并时,是有可能发生冲突的,如下图所示,dev分支,将11111写入ReadMe文件,并添加提交,master分支,将2222写入ReadMe文件,并添加提交,将dev分支合并到master分支时,就发生了冲突,因为git无法确定要保存哪一个,就如同C++中的菱形继承中的二义性问题
要想解决合并冲突问题,就需要我们手动修改冲突的内容,选择其中一个,然后再添加提交即可!
用git log --graph --pretty=oneline --abbrev-commit命令可以查看合并情况
分支管理策略
fast-forward模式合并,删除分⽀后,查看分⽀历史时,会丢掉分⽀信息,看不出来最新提交到底是merge进来的还是正常提交的,但在合并冲突部分,解决合并冲突,就能知道是merge进来的还是正常提交的!
要想不以fast-forward模式合并,可以采用 git merge --no-ff -m “日志信息” 分支名,来合并
当我在dev分支上开发时,突然发现master分支上有个bug需要解决,而我才开发到一半,没办法提交,这时,就需要保存工作区现场,可以用git stash命令,来讲工作区信息隐藏,用git stash list可以查看刚才的隐藏信息保存在哪个分支上,用git stash pop命令来恢复现场信息,并将stash删除
建议:当我们建立分支去写代码要合并时,可以先将master分支合并到当前分支,如果发生合并冲突,就可以在当前分支解决,从而不会影响master
远程仓库
如下图,是在gitee上新建远程仓库的步骤,Readme文件是一些说明,可以自己去填写,便于别人使用,比如软件的安装步骤等等,而Issue则可以用来提bug等等,Pull Request在远程合并分支时使用, 比如你在dev分支开发完,需要合并到master分支,就需要填写Pull Request申请单
而要想本地与远程建立联系,就必须先将仓库拷贝到本地,即使用git clone 下面的url
在本地查看远程仓库,可以用git remote命令,想查看详细信息,可以带-v选项,远程仓库的默认名称是origin,下面显示了拉取和推送的地址,表明可以向远程仓库推送信息,也能获取远程仓库的信息
向远程仓库推送,可以用git push <远程主机名> <本地分⽀名>:<远程分⽀名>来推送,如果本地分支名和远程分支名相同,则可以省略冒号及它后面的,如下图,我删除了本地仓库的文件,同时也想把远程的也给删掉,就用到了push操作
拉取远程仓库内容和推送一样,只不过要把push改为pull,如下图,先在远程仓库创建了一个file.txt文件,并写入hello world,在本地pull后,就能把远程仓库的内容拉取到本地仓库中
配置Git
在上面创建仓库时,有一个添加ignore文件,可以勾选,就会在远程仓库生成该文件,该文件用于添加提交文件时,可以忽略指定的部分文件,比如写入了账号密码信息的文件,我不想推送,让别人看到,我就不提交,但文件太多了,add 指定文件太麻烦,就只能add . ,所以就有了ignore文件的产生,直接在该文件中写入你想忽略的文件即可,如下图所示。
如果是使用的*.txt,来忽略所有txt后缀文件,而又要某个.txt文件不被忽略,就能在该文件前面加个!xxx.txt,表示不忽略。git add -f可以强制添加文件,但不建议使用
给命令配置别名
如下图,这条命令太长了,写起来太麻烦,就可以对其起别名
如下图,用git config --global alias.别名 ‘命令’
因为commit id太长了,很难记住,所以我们可以用标签来作为commit的别名,这样也方便后续使用
可以用git tag 标签名来创建一个标签,git tag查看标签
如下图,可以看出,默认打的标签是打在最新的一次commit上的
如下图,给指定commit打标签,用git tag 标签名 commit id