Git详细教程
- 前言
- git常用命令
- 版本管理
- 远程仓库
- 分支管理
- 正文
- git版本管理
- 版本回退
- 工作区和暂存区
- 工作区
- 版本库(Repository)
- 撤销修改
- 删除文件
- git远程仓库
- github使用
- 添加远程库
- 小结
- 从远程库克隆
- git分支管理
- 创建和合并分支
- git merge vs git rebase
- 解决冲突
- 第一种情况
- 多人协作
- BUG分支
- 总结
- 参考连接
前言
大家好,我是练习两年半的Java练习生,今天我们来学习一下我们经常用的Git。相信大家对Git已经不陌生了,但你真的了解其中的运作机制吗?你知道rebase 和 merge 的区别吗?让我们一起来学习吧!!
git常用命令
我们先来带大家简单过一下文章中出现的命令,方便大家复习记忆,如果看不懂没关系,接着往下看就可以了~
版本管理
将文件添加到暂存区
git add [file]
git add .
提交更改到本地仓库
git commit -m [message] // 将暂存区的所有更改提交到本地仓库,附带一条信息
git commit --amend //修改最后一次提交的信息
查看提交历史
git log // 查看所有提交历史
git log --oneline // 以简洁的方式查看提交历史
git log -p [file] //查看指定文件的提交历史
切换分支或回退版本
git checkout [branch] // 切换到指定分支
git checkout -b [branch] // 创建一个新的分支并切换到该分支
git checkout [commit] // 回退到指定版本
版本回退
git reset [版本]
git revert [版本]
远程仓库
克隆仓库
git clone [url]
管理远程仓库
git remote // 列出所有远程仓库
git remote add [name] [url] // 添加一个新的远程仓库
git remote add origin https://github.com/user/repo.git
git remote remove [name] // 删除一个远程仓库
获取远程仓库的更改
git fetch [remote] [branch]
获取并合并远程仓库的更改
git pull [remote] [branch]
推送更改到远程仓库
git push [remote] [branch]
查看远程分支
git branch -r
管理标签
git tag //列出所有标签
git tag -a [name] -m [message]//创建一个新的附注标签,附带一条信息
git push --tags // 将所有本地标签推送到远程仓库
创建本地分支和远程仓库分支
git checkout -b master o/master
分支管理
分支创建:git branch [名字]
分支查看:git branch
分支切换:
- git checkout [名字]
- git checkout [分支]^
- git checkout [分支]~4
分支合并:
- git merge [branch] // 合并分支
- git rebase [branch] //变基
拾取提交
git cherry-pick [commit] //将指定的提交应用到当前分支
正文
git版本管理
- git status
作用: 让我们时刻掌握仓库当前的状态
- git diff
作用: 顾名思义就是查看 difference , 显示的格式正是Unix通用的diff格式
微软txt在utf8格式有什么问题?
当我们在记事本或WordPad中输入文本时,按下回车键会在文本中插入回车符和换行符,这些符号通常被称为"换行符"或"行结束符"。
在Windows操作系统中,回车符通常用"\r"表示,而换行符通常用"\n"表示。
因此,如果我们在记事本或WordPad中输入两行文本:
第一行文本
第二行文本
因此,如果我们在记事本或WordPad中输入两行文本:
第一行文本\r\n第二行文本
其中,“\r\n"表示回车符和换行符的组合,这是一种常见的文本格式,特别是在Windows操作系统中。
在记事本中,当我们按下回车键时,记事本会自动将”\r\n"插入到文本中。这就意味着在记事本中,两个换行符之间的文本通常被视为一个段落,而不是一个换行符。例如,在记事本中输入以下文本:
第一段落第一行 第一段落第二行
第二段落第一行 第二段落第二行
则实际上在文本中,这些内容如下所示:
第一段落第一行\r\n第一段落第二行\r\n\r\n第二段落第一行\r\n第二段落第二行
注意,第一段落和第二段落之间有两个换行符,而第一段落内部的两行文本之间只有一个换行符。当我们在记事本中打开这个文件时,第一段落将显示为一个段落,而不是两个单独的行。
另一方面,在WordPad中,两个换行符通常被视为两个段落之间的分隔符。因此,如果我们在WordPad中输入相同的文本,并保存为.txt文件,则在记事本中打开它时,第一段落将显示为两个单独的行,而不是一个段落。这是因为WordPad使用单个换行符来表示段落的结束,而不是使用两个换行符。
版本回退
- git log
作用: 查看我们提交的历史记录,git log命令显示从最近到最远的提交日志
- git reset
作用:
用法:git reset [版本] //本地仓库
特点:
- 彻底回退到指定版本,干净清爽
- 提交时间先清晰,没有冗余
缺点:
- 记录彻底删除,恢复比较麻烦
执行 git reset C1之后,会回退到C1版本
这样回退之后,前面的记录是不可见的,相当于坐了时光机回到了过去
如果你想要取消上面的回退操作,那应该怎么办呢??
- git reflog
作用: 这个命令记录了你的每一次操作,你可以找到对应的版本号,从而回到刚刚回退的地方
问题:如果工作区里的文件还没有被git托管,用reset会导致文件被删除吗?如果加入暂存区之后再reset呢?
答:没有被托管前文件是不会受影响的。如果文件被add到暂存区,那么reset后会被删除
- git revert
作用: 使用一个新的commit来回滚你想要的状态,通过撤销/撤回/反提交来实现,而reset是直接将HEAD指针指向回退的版本
特点:
- 不会删除记录,而是产生新纪录
- 撤销时可能会产生冲突
- HEAD一直向前
工作区和暂存区
工作区
就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区
版本库(Repository)
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
想要理解HEAD指针,强烈建议打开这个练习网站:https://oschina.gitee.io/learn-git-branching
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
大家可自行新增一个文件,先git add 文件名,再查看git status ,然后再git commit 。
撤销修改
- git checkout – readme.txt
作用:
可以丢弃工作区的修改
这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
- git reset HEAD
作用:
可以把暂存区的修改撤销掉(unstage),重新放回工作区
git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。
前面两种都是还未提交到版本库的撤销情况,但如果已经提交到了本地版本库,那么要如何撤销呢?
就是我们上一小节讲到的版本回退内容了,注意如果推送到了远程仓库,那么就回退不了了
最新版git 似乎把命令改为 git-restore 了,可参考:https://git-scm.com/docs/git-restore/zh_HANS-CN
删除文件
- git rm 文件名
作用:命令git rm用于删除一个文件。
如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
git远程仓库
github使用
第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key
$ ssh-keygen -t rsa -C "youremail@example.com"
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。
如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
添加远程库
首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:
在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:
现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:
$ git remote add origin git@github.com:yougithubname/learngit.git
请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。
下一步,就可以把本地库的所有内容推送到远程库上:
$ git push -u origin master
额外知识
github创建仓库时默认仓库名为 origin ,分支为main 。
而我们本地只有master 分支,那么会导致推master分支的时候,出现
error: src refspec master does not match any
为什么会出现这种情况?
听说是美国人认为master是歧视黑人
如何解决呢?
在setting >> Branches 中修改master为默认分支
小结
要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git;
关联一个远程库时必须给远程库指定一个名字,origin是默认习惯命名;
关联后,使用命令git push -u origin master第一次推送master分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
从远程库克隆
git clone git@github.com:yourname/仓库名.git
git clone https://github.com/yourname/仓库名.git
上面一种方法会快一些,下面的话需要每次输入口令
git分支管理
分支管理模块是git的一个精髓
但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
这里再次强烈推荐去看看这个网站,里面可以让你更简单的理解分支这个概念
https://oschina.gitee.io/learn-git-branching
创建和合并分支
创建分支命令:
git checkout -b 分支名 或者 git switch -c // 表示创建并切换到新的分支
git branch 分支名 // 创建一个分支
git checkout 分支名 或者 git switch // 切换到某个分支
git branch //查看分支情况
git merge 合并某分支到当前分支
如图,当前HEAD指针指向的是dev 分支,显示为dev*,并且两个分支提交了不同的内容,是两个互补影响的分支。
HEAD指针可以指向某个分支,也可以指向某个记录,切换分支的时候,实际上就是切换HEAD指针
那么如何进行分支合并呢?
- git merge 分支 // 将分支合并到当前分支上,当前分支为master
优势是保留了分支结构和历史提交目录,但同时也导致了提交历史会被大量merge污染
- git rebase
rebase 命令是一个经常听到,但是大多数人掌握又不太好的一个命令。rebase 合并往往又被称为 「变基」
以 master 分支为基,对 feautre 分支进行变基:
git checout feature git rebase master
如下图所示:
git rebase 的优势是可以获得更清晰的项目历史。首先,它消除了 git merge 所需的不必要的合并提交;其次,正如你在上图中所看到的,rebase 会产生完美线性的项目历史记录,你可以在 feature 分支上没有任何分叉的情况下一直追寻到项目的初始提交。
git merge vs git rebase
git merge:
- 记录下合并动作,很多时候这种合并动作是垃圾信息
- 不会修改原 commit ID
- 冲突只解决一次
- 分支看着不大整洁,但是能看出合并的先后顺序
- 记录了真实的 commit 情况,包括每个分支的详情
git rebase:
- 改变当前分支 branch out 的位置
- 得到更简洁的项目历史
- 每个 commit 都需要解决冲突
- 修改所有 commit ID
解决冲突
出现冲突的情况有两种:
- 在远程仓库中,被其他合作者修改过文件,在pull的时候,出现冲突
- 如果两个分支对同一个文件产生不同的修改,在合并时,就会出现冲突
第一种情况
如果两个分支对同一个文件产生不同的修改,在合并时,就会出现冲突
文件中会出现,<<<<<<<,=======,>>>>>>>标记出不同分支的内容
test 1
bad things
888
111
<<<<<<< HEAD
master
=======
main
>>>>>>> 6b26656 (main)
用VS Code打开,解决手动解决冲突
然后,通过以下命令重新提交,并执行完合并
git add .
git commit -m "coflict fixed"
git rebase --continue //如果是merge的话,只需要上面两个就行
git log --graph --pretty=oneline --abbrev-commit
通过这个命令可以查看分支合并情况
多人协作
- git remote // 查看远程库的信息
- git remote -v //显示更详细的信息
- git branch --set-upstream branch-name origin/branch-name; //建立本地分支和远程分支的关联
- git checkout -b branch-name origin/branch-name // 在本地创建和远程分支对应的分支
一般如果在push分支到远程时,发现推送不了,那么一般需要先pull分支,手动解决冲突之后再进行push
BUG分支
软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
git stash // 保存工作现场
git stash list //查看工作现场
git stash apply //恢复工作现场,但不删除stash内容
git stash pop // 恢复工作现场,恢复的同时把stash内容也删了
保存现场后,创建一个bug分支,然后进行bug修复,修复完成后,切换到master分支,完成合并,再删除bug分支
总结
好啦,以上就是我们今天要介绍的全部内容,希望能帮助你更好的理解Git,并在日常开发中灵活使用这个工具~~
同时,Git简单易懂的动画学习 ,也非常推荐大家去这个网站上学习一下,里面用生动的动画告诉你git 的各种操作,可能花几个小时就能把里面的案例做完了 ,一定会对你理解Git有一定帮助的!!
如果大家还有什么问题,欢迎私信或者在评论区提出来,让我们一起学习进步!!!
参考连接
https://oschina.gitee.io/learn-git-branching/?NODEMO
https://juejin.cn/post/6945572770843459615
https://www.liaoxuefeng.com/wiki/896043488029600/900004111093344