Git入门教程(Git 2.42)
本教程使用Git版本为2.42,以下内容均为我作为大学生的身份、在实际操作中常用到的命令,今日将其总结并记录。
本教程对个人开发者应该是足够用的,但是对于团队开发应该仍然不够。
所有指令一览
本教程会涉及如下指令:
常用
git init
:初始化git remote add origin <url>
:添加远程仓库
git status
:查看当前工作区和暂存区的状态
git add .
:添加所有文件到暂存区git commit -m "提交信息"
:提交修改到本地仓库git push origin <分支名>
:将本地仓库更新到远程仓库,首次推送需加-u
设置上游分支
git clone <url>
:克隆远程仓库到本地git pull origin <分支名>
:拉取默认远程仓库的<分支名>
分支内容到本地
回档
git restore --staged <文件名>
:撤回<文件名>
的git add,但是保留工作区<文件名>
的修改git restore <文件名>
:撤回工作区<文件名>
的修改(Git 2.23引入,更推荐)git checkout -- <文件名>
:撤回工作区<文件名>
的修改(旧版本)
git log --oneline
:以简洁的方式查看commit历史
git reset --soft <哈希值>
:软回档,回档到对应<哈希值>
commit之后,同时保留下一次commit暂存区的修改git reset --hard <哈希值>
:硬回档,回档到对应<哈希值>
commit之后,但是不保留下一次commit暂存区的修改
git revert <哈希值>
:以merge的方式,回档到对应<哈希值>
分支修改之前的状态,也就是对应<哈希值>
分支的上一次commit之后的状态(更准确来说不是回档,是撤销<哈希值>
对应的commit修改,但<哈希值>
之后的commit修改仍然存在)git show <哈希值>
:查看<哈希值>
的内容,revert到含merge节点时需要使用该命令git revert -m <分支代号> <哈希值>
:回档对应merge之前对应<哈希值>
分支的状态
分支
git branch
:查看本地仓库所有分支git branch -a
:查看所有分支(包括远程)git branch -r
:查看远程仓库所有分支git branch -m <旧分支名> <新分支名>
:重命名分支git branch -d <分支名>
: 删除分支git push origin -d <分支名>
: 删除远程分支
git checkout -b <新分支名>
:创建并切换至新分支(旧版本)git checkout <分支名>
:切换分支(旧版本)git switch -c <新分支名>
:创建并切换至新分支(Git 2.23引入,更推荐)git switch <分支名>
:切换分支(Git 2.23引入,更推荐)
其他
git -v
:查看git版本git remote show origin
:显示远程仓库的详细信息
git fetch origin <分支名>
:从远程拉取对应分支的最新版本,但不合并git fetch -a
: 获取所有远程分支git diff <本地分支名> origin/<远程分支名>
:查看当前分支与远程分支的差异git merge <分支名>
:将<分支名>
合并到当前分支git fetch -p
:清理在本地存在但是已删除的远程分支
git commit --amend
:修改最近一次提交
第一次使用
添加github远程
详情可参照网上教程,或者我的笔记
在github创建远程仓库
1、在自己的profile
页面,点击右上角的+
号,然后点击New repository

2、填写仓库名字、选public、注意不添加README文件、然后点Create repository

3、然后就可以看到官方示例的仓库初始化代码(图里面我字打错了)

在本地创建仓库
1、随便选一个位置,新建文件夹,进入文件夹,然后打开git bash
win11的用户,按住shift点击鼠标右键,可以直接展开折叠选项
2、在git bash中输入git init
初始化,此时会发现文件夹下出现了.git
文件夹,这个.git
文件夹就是后面提到的本地仓库

3、在文件夹下创建你想要上传到github仓库的文件,这里我直接新建1.txt
在git bash中输入git staus
可以查看git状态,如下图可以看到红色的1.txt,且标记为Untrack未追踪

4、git add <文件名字>
将文件添加到暂存区,此时git staus
可以发现,红色的1.txt变成绿色了,且标记变成了to be commited等待被提交

5、这里我有新建了两个文件,并把它们add到暂存区,其中git add .
的.
代表所有文件,这个会比一个一个添加文件快速

6、git commit -m "提交信息"
将文件提交到本地仓库,-m是一个参数,后面用双引号括起来你的提交信息。提交之后查看git staus
,发现working tree clean工作树干净了
用工单来举例的话,git add就是挂起工单,git commit就是解决工单,即修改信息已经提交到本地仓库了

到这一步,如果你不用远程仓库,其实也是可以的
提交到远程仓库
1、git remote add origin <ssh or https>
添加远程仓库地址,这个在初始化代码的时候github会自动生成

2、git branch -M main
将本分支强制重命名为main,-M就是强制的意思。你会注意到,github新创建的仓库的默认分支名是main,但是git bash默认是master(不过我不清楚最新版git bash有没有改过来啊),如果最后是从master push到main的话,会出问题
3、git push -u origin main
,-u是第一次上传需要加的参数,后面就不用加了,origin算是一个默认的参数,一般不会改变,后面的main代表的是你要push的分支
此时刷新你github仓库的界面,发现文件已经上传了

小结
除第一次上传是按照以上的步骤,以后的上传可按照下面三个步骤:
1、git add .
添加所有文件到暂存区
2、git commit -m "提交信息"
将所有暂存区的更改提交到本地仓库
3、git push origin main
将本地仓库的内容push到远程仓库

注:
1、善用git status
查看git状态
2、用vscode的源代码管理会更加方便
git pull与冲突解决
git clone
现在我们到github上复制仓库的url,如下图所示,复制https

然后回到刚才放代码的地方,把存代码的文件夹删了,然后重新在文件夹里使用git clone
命令,发现没有报错


然后重新创建新的文件并上传(4.txt
),均未报错。这说明这个本地的文件夹我们是可以删除和变动的

然后我们在这个clone不删的情况下,又换一个目录位置,继续clone然后上传新文件(5.txt
),发现也没有报错,这说明一台电脑里我们可以有多个clone的文件夹(当然这个没什么意义)


git pull
但是这时候,我们回到刚才的那个文件夹,重新创建一个新的文件(6.txt
),就会出现如下报错

因为你刚才在另外一个文件夹上传了,但是这个原来的文件夹没有同步,所以出现了冲突,这时候应使用git pull origin + <分支名>
进行拉取
在你执行git pull的命令之后,会出现如下界面,这是进入到默认的vim编辑器中了,关于vim编辑器的使用可以参考其他的教程

这是git拉取了远程仓库到本地自动merge合并时,你需要提交的merge信息,但我们也可以不用管。只需记住,按一下键盘左上角的ESC
,然后输出:q!
(注意命令会在窗口左下角显示),回车,即可退出vim编辑器

之后就会发现,当前目录下多了远程仓库里的5.txt

这时候我们查看git status,发现比远程仓库多了两个commit,这是因为我们有一个新建6.txt
的commit,然后再加上刚才merge的commit,一共有两个

回到github的仓库界面我们也能看到是多了两个commit,和我上述说的一致


冲突解决
我们直接在github上面打开1.txt
,然后修改文件内容为aaaaaaaa


然后回到本地打开1.txt
,修改文件内容为bbbbbbb

此时你查看status的时候会发现1.txt
的状态是modified,已修改

然后执行一套上传流程,发现报错

按照要求git pull之后,提示在1.txt
中有冲突

我们进到1.txt
中会发现两个版本文件的冲突用<<<====>>>符号进行了分隔,上面的是本地分支,标记为HEAD
,下面的是远程分支,后面的是这个分支的哈希值

我们修改冲突,假设我们同时保留aaaaa和bbbb,如下图

此时你不能直接git push,不然会报错。而是应该用git add+commit的方式标记冲突解决,如下图所示

且注意到commit之后我们的main后面的MERGING状态消失了。这时候我们再git push,发现上传成功了

回到github上面也可以看到我们的两次commit,一次本地修改1.txt
bbbbb的提交,一次git pull之后的merge

如何回档
撤销git add
现在我们在本地目录下删除6.txt
,这时候git status会发现6.txt
的状态为deleted

然后我们git add一下再git status,发现6.txt
的颜色从红色变成了绿色,这是未来我们可以用来区分哪些文件没有提交到暂存区的方式

撤销git add的文件,使用git restore --staged <文件名>
,如下图,此时git status发现6.txt
的颜色又变回了红色,这说明“6.txt
被删除的消息”被撤销“提交到暂存区”了

但是工作目录中的6.txt
并没有回来,要想恢复删除的文件的话,再执行git restore <文件名>
(不用加–staged参数)即可
小结
对于已经删除但没有git add的文件:直接git restore <文件名>
对于已经删除且已经git add的文件:先git restore --staged <文件名>
撤销add,然后再git restore <文件名>
恢复文件
撤销git commit
使用git log
可以查看commit历史(如果信息太多,键入q退出显示),加上--oneline
参数可以更简洁,如下图所示
这里我们先把删除6.txt
的消息提交了,再git log --oneline
,发现历史已经更新了,且每次提交都有自己的哈希值

执行git reset + <哈希值>
,可以撤回提交。但注意,每次提交前面的哈希值,是代表这次提交之后的状态
这里我们执行git reset --soft <哈希值>
,这个是软回档,即只撤销git commit,但是不撤销git add,如下图所示,这时候会发现,6.txt
变成绿色、等待commit的状态

如果想要让文件直接回来,执行git reset --hard <哈希值>
,如下图所示,此时git status发现工作树干净,因为这是回档节点刚刚commit后的状态

这个是硬回档,会丢失回档节点之后的所有提交,慎用,如下图,我的第九次提交的信息已经没有了

不过有一种更安全的方式回档,即使用git rever <哈希值>
,revert方式会创建一个新的merge,这样的话以前的commit就都会还在,如下图所示(同样中间会进到vim里面让你填revert的信息)
(注,刚上述回档到merge,我又重新搞了第九次提交和第十次提交)


值得注意的是,只考虑代码状态的话,revert代码会回到commit之前的状态,reset是回到commit之后的状态
因此如果我们revert到merge的节点,如下图所示发现会报错,我们需要选择我们需要回档的分支,使用git show <哈希值>
可以查看两个分支的差异
git show注意到Merge参数后面有两个哈希值,前面的代号为1,是下面红色的部分;后面的代号为2,是下面绿色的部分

使用-m参数来选择revert的分支,执行git revert -m <代号1或者2> <哈希值>
,同样需要填写revert的信息,即可回档


此时如果我们再选择-m 2
,会提示有冲突,这就又回到前面说解决冲突的步骤了

解决冲突后,同样是add+commit操作,注意此时右上角的状态是专门的REVERTING状态

小结
使用git log --oneline
查看提交历史
git reset --soft <哈希值>
:软回档,只撤销git commit,但是不撤销git addgit reset --hard <哈希值>
:硬回档,全部撤回
注意:reset会丢失撤销节点之后所有commit的信息,使用revert能够更安全的撤回
git revert <哈希值>
:撤回到commit之前的状态
如果是revert到merge节点,需要git show <哈希值>
查看两个分支的差别,然后git revert -m <分支代号> <哈希值>
撤回
注意:reset是撤回到节点commit之后(对硬回档来说)的状态,revert是撤回到commit之前的状态
fork、分支创建与PR
如果我想给别人的仓库合并代码,我需要先fork,然后在fork的仓库上修改,最后PR过给原来的仓库等待审核
我用我的小号新建了一个仓库,如图所示,点击fork,会创建一个自己的仓库,fork相当于复制


可以看到fork的仓库下面会有fork专门的标识

我们把fork仓库clone到本地来,使用git checkout -b <分支名>
创建并且切换分支,-b参数就是对于创建新分支而言的,如果分支存在的话,直接checkout过去就行
然后我们走一条流程git push上去

此时回到github仓库,发现已经可以找到我们刚才创建的新分支了

点击Compare & pull request,可以打开一个向原仓库合并的PR

填写你的PR标题、描述,最后创建PR
在该界面上方,可以看到你是从fork仓库的diraw分支提交PR到原仓库的main分支

然后你就会自动跳转到原仓库下,整个PR的流程也就结束了

回到本地工作目录,我们可以使用git branch
来查看本地仓库的所有分支,在git2.23版本之后,推荐使用git switch <分支名>
来切换分支,详情请见补充/过时命令板块

查看git版本使用git -v

补充
更多细节
HEAD概念
git reset理解
origin理解
文件状态
过时命令
这里介绍一些很容易在网上的一些古早教程看到的过时命令,主要是针对git checkout
取消暂存:Git 2.23之前是git reset HEAD <file>
,现推荐使用git restore --staged <file>
取消工作区修改:Git 2.23之前是git checkout -- <文件名>
,现推荐使用git restore <文件名>
创建并切换分支:Git 2.23之前是git checkout -b <new-branch>
,现推荐使用git switch -c <new-branch>
,切换分支同理
在Git 2.23之后,git checkout被拆分为git restore和git switch,主要是因为git checkout职责过多,既能切换分支,又能恢复文件,容易误操作。
补充命令
git branch -d <分支名>
: 删除分支
git push origin --delete <分支名>
: 删除远程分支
git fetch --all
: 获取所有远程分支
.gitignore 文件:管理哪些文件不被 Git 跟踪
高级命令
git stash:临时保存未提交的修改
git rebase:变基
git cherry-pick:选择性地应用某个提交
git tag:管理版本标签
git bisect:二分查找定位问题提交
git submodule:管理子模块
git config