git系统学习笔记(基于acwing课)
前言
这是基于acwing中linux系统课下的git网课写的笔记。
由于自己没系统学过就直接上手一边用一边现查然后发现玩不下去,所以转而系统学习,课前提要的时候y总也说他学习的时候也是这样的感受,所以让我们不要像学vim、tmux和ssh那样像学工具一样学习,一定要先系统地学完再使用git命令。
由于git命令实在过于复杂(我认为倒也不是命令复杂,而是里边的逻辑概念很难形成一个清晰的认知,哪怕已经有点概念了,只要不是相当明确,就会出现同样的需求前一次感觉已经谈不上稀里糊涂有点概念地实现成功了,重新再实现一遍居然又遇上新的报错),我写了此篇笔记,用来之后翻看用。
acwing的讲义
acwing有提供过一套讲义,我先将它复制到此处。
git基本概念
- 工作区:仓库的目录。工作区是独立于各个分支的。
- 暂存区:数据暂时存放的区域,类似于工作区写入版本库前的缓存区。暂存区是独立于各个分支的。
- 版本库:存放所有已经提交到本地仓库的代码版本
- 版本结构:树结构,树中每个节点代表一个代码版本。
git常用命令
git config --global user.name xxx
:设置全局用户名,信息记录在~/.gitconfig
文件中git config --global user.email xxx@xxx.com
:设置全局邮箱地址,信息记录在~/.gitconfig
文件中git init
:将当前目录配置成git仓库,信息记录在隐藏的.git文件夹中git add XX
:将XX文件添加到暂存区git add .
:将所有待加入暂存区的文件加入暂存区
git rm --cached XX
:将文件从仓库索引目录中删掉git commit -m
“给自己看的备注信息”:将暂存区的内容提交到当前分支git status
:查看仓库状态git diff XX
:查看XX文件相对于暂存区修改了哪些内容git log
:查看当前分支的所有版本git reflog
:查看HEAD指针的移动历史(包括被回滚的版本)git reset --hard HEAD^
或git reset --hard HEAD~
:将代码库回滚到上一个版本git reset --hard HEAD^^
:往上回滚两次,以此类推git reset --hard HEAD~100
:往上回滚100个版本git reset --hard 版本号
:回滚到某一特定版本
git checkout — XX
或git restore XX
:将XX文件尚未加入暂存区的修改全部撤销git remote add origin git@git.acwing.com:xxx/XXX.git
:将本地仓库关联到远程仓库git push -u
(第一次需要-u以后不需要):将当前分支推送到远程仓库git push origin branch_name
:将本地的某个分支推送到远程仓库git clone git@git.acwing.com:xxx/XXX.git
:将远程仓库XXX下载到当前目录下git checkout -b branch_name
:创建并切换到branch_name
这个分支git branch
:查看所有分支和当前所处分支git checkout branch_name
:切换到branch_name这个分支git merge branch_name
:将分支branch_name合并到当前分支上git branch -d branch_name
:删除本地仓库的branch_name分支git branch branch_name
:创建新分支git push --set-upstream origin branch_name
:设置本地的branch_name
分支对应远程仓库的branch_name
分支git push -d origin branch_name
:删除远程仓库的branch_name
分支git pull
:将远程仓库的当前分支与本地仓库的当前分支合并git pull origin branch_name
:将远程仓库的branch_name
分支与本地仓库的当前分支合并
git branch --set-upstream-to=origin/branch_name1 branch_name2
:将远程的branch_name1
分支与本地的branch_name2
分支对应git checkout -t origin/branch_name
将远程的branch_name
分支拉取到本地git stash
:将工作区和暂存区中尚未提交的修改存入栈中git stash apply
:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素git stash drop
:删除栈顶存储的修改git stash pop
:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素git stash list
:查看栈中所有元素
acwing开发的仿github平台
网址:git.acwing.com
y总说马云的gitee广告太多,不喜欢,所以自己开发了这个。
这个平台可以国内网进且快一点,且目前基本只有acwing的同学知道,氛围会好一点。
y总说了,是免费的,大家也可以拿这个替代github。
我去看了下,前端界面开发得挺好看的。
(但是好像终端得用AC terminal,而AC terminal只有买了课的同学才能用,且给每个人分的带宽不多,亲测是很卡的。)
网课笔记
树模型
- git其实相当于树模型,HEAD其实类似于头指针。
因为这是个树模型,所以HEAD也可以在不同分支间切换。 - 仓库信息在.git文件夹内
1
2
3
4
5
6
7
8
9zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ ls -a
. .git CONTERIBUTING.md HelloWorld db.sqlite3 statics templatetags
.. .vscode CONTRIBUTING.md TestModel manage.py templates
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ cd .git
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/.git$ ls -a
. COMMIT_EDITMSG HEAD branches description index logs packed-refs
.. FETCH_HEAD ORIG_HEAD config hooks info objects refs
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/.git$ cat HEAD
ref: refs/heads/Lucy1
版本
git status
可以用来查看当前是否有文件没加进来,比如我给文件夹里添加一个111.html
.
可以对比一下git add .
之前和之后的git status
给的提示。1
2
3
4
5
6
7
8
9
10
11
12
13
14zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git status
On branch Lucy1
Untracked files:
(use "git add <file>..." to include in what will be committed)
templates/111.html
nothing added to commit but untracked files present (use "git add" to track)
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git add .
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git status
On branch Lucy1
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: templates/111.htmlgit commit -m "给自己或合作者看的备注信息"
记得要加-m
!!!git commit -m "给自己或合作者看的备注信息"
命令之后,将我们当前暂存区的版本存到了我们当前分支的下一个节点,并将HEAD指向这个点,并且这个节点的记录存下备注信息。注意可以使用
git diff XX
查看XX文件相对于暂存区修改了哪些内容关于
git rm --cached XX
和git restore --stage XX
:这俩都可以从暂存区里撤回点东西,区别是,rm是直接删,而restore是回滚。git log
是从最初的空节点沿着当前分支走到当前节点,只有这条路径的log。
所展示的内容,放最上面的是最新修改,越往下越旧,直到走到空节点。- 有个命令叫
git log --pretty=oneline
,这样每个节点只展示一行。
部分log展示如下(只包含最近的几条信息,先前的太多了就不展示了):1
2
3
4
5zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/templates$ git log --pretty=one
line
79c2e08e07bf9f7916544c8641efee252b66b420 (HEAD -> Lucy1) add 111.html
80bab04e71ae3ec61af0cf46ba58cdfee8cc6877 delete 111.html
6024a913bf3557b9423a832f7a3d50a08d1e0320 add 111.html
- 有个命令叫
往前回滚版本
git reset --hard HEAD^
一个^
代表回滚一个版本,两个^
代表回滚两个版本,依此类推。
连续执行两次git reset --hard HEAD^
命令的效果等同于git reset --hard HEAD^^
,而不等同于回滚回去再滚回来。- 回滚完之后,HEAD指针会前移,而
git log
只能显示根节点到HEAD的路径。虽然这里的回滚,不会将之前的内容删掉,但是git log
已经看不到回滚前的了,那么如何回退回来呢? - 用
git reflog
命令展示HEAD的移动记录。(部分reflog展示)1
2
3
4
5zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git reflog
80bab04 (HEAD -> Lucy1) HEAD@{0}: reset: moving to HEAD^
79c2e08 HEAD@{1}: commit: add 111.html
80bab04 (HEAD -> Lucy1) HEAD@{2}: commit: delete 111.html
6024a91 HEAD@{3}: commit: add 111.html - 在reflog里可以看到每个版本的编号,这个编号是hash值的前7位,这里的版本号用来跳转到任意一个节点(因为所有创建过的目录,HEAD一定是走过的,所以一定会在reflog里出现过)。 (部分reflog展示)
1
2
3
4
5
6
7zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git reflog
79c2e08 (HEAD -> Lucy1) HEAD@{0}: reset: moving to 79c2e08
80bab04 HEAD@{1}: reset: moving to 80bab04
80bab04 HEAD@{2}: reset: moving to HEAD^
79c2e08 (HEAD -> Lucy1) HEAD@{3}: commit: add 111.html
80bab04 HEAD@{4}: commit: delete 111.html
6024a91 HEAD@{5}: commit: add 111.html
这里可以关注到,回滚回某个版本的时候,版本号和回滚的版本号一致,比如这里出现了两个79c2e08和两个80bab04。 - 关于
git reset --hard HEAD^^
:可以发现这里的HEAD^^不是回滚reflog的前两个版本,而是回滚git log的前两个版本(git log是沿着当前分支从根节点走到当前HEAD节点路径的节点)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git log
commit 79c2e08e07bf9f7916544c8641efee252b66b420 (HEAD -> Lucy1)
Author: zstu21 <3435657471@qq.com>
Date: Wed Dec 13 23:46:55 2023 +0800
add 111.html
commit 80bab04e71ae3ec61af0cf46ba58cdfee8cc6877
Author: zstu21 <3435657471@qq.com>
Date: Wed Dec 13 23:21:54 2023 +0800
delete 111.html
commit 6024a913bf3557b9423a832f7a3d50a08d1e0320
Author: zstu21 <3435657471@qq.com>
Date: Wed Dec 13 23:18:21 2023 +0800
add 111.html
# (此处省略前边历史)
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git reset --hard HEAD^^
HEAD is now at 6024a91 add 111.html
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git reset --hard HEAD^^
HEAD is now at 6024a91 add 111.html
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git reflog
6024a91 (HEAD -> Lucy1) HEAD@{0}: reset: moving to HEAD^^
79c2e08 HEAD@{1}: reset: moving to 79c2e08
80bab04 HEAD@{2}: reset: moving to 80bab04
80bab04 HEAD@{3}: reset: moving to HEAD^
79c2e08 HEAD@{4}: commit: add 111.html
80bab04 HEAD@{5}: commit: delete 111.html
6024a91 (HEAD -> Lucy1) HEAD@{6}: commit: add 111.html
# (此处省略前边历史)
- 回滚完之后,HEAD指针会前移,而
返回到上次保存(返回目前暂存区的版本,不是返回暂存区上一次的版本,就比如我往
111.html
中添加了111
这句话,没git add .
,那我git restore .
后就是把111
这行话删除,回滚到111.html
没有111
这句话的状态)的版本:git restore .
:全部文件返回上次保存的版本。git restore XX
:XX文件返回上次保存的版本。
git add XX
也可以将删除XX文件的记录添加到暂存区内。1
2
3
4
5
6
7
8zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/templates$ rm 111.html # linux命令
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/templates$ git add 111.html
zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet/templates$ git status
On branch Lucy1
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: 111.htmlgit add XX YY
这样并排地写两个文件,意为把XX和YY两个文件的信息都添加到暂存区。这里若是误删,可以用
git restore XX
恢复XX文件(相当于从回收站还原文件)。
这里需要注意的是,
git log
和git reflog
记录的版本都只有持久化后的版本的,只有git commit -m "XX"
后才会生成一个新版本。
暂存区无变化的情况下,用git commit -m "XX"
命令多次的结果是,无论在git log
还是git reflog
中,都不会生成新的版本,只有第一次commit的记录。
目前都是对本地的操作,跟云端没有关系。
github上查看历史版本
现在开始讲云端
github上绿色的
<>code
按钮下边有个n commits
的按钮,点击就可以查看每个分支的commits
使用
git reset --hard [你的commit id]
可以恢复历史版本,然后再用git push命令推送到远程仓库。这里的
commit id
是版本号中提交到远程仓库的部分,比起git reflog
命令显示的版本号,缺少回滚部分。git reflog
中(我目前所看到的只有三种,说明这三种最常见):1
2
36024a91 HEAD@{8}: checkout: moving from branch1 to branch2
731779f HEAD@{16}: commit: delete 111.html
6024a91 HEAD@{17}: reset: moving to HEAD^^分别为checkout,commit和reset,其中github仓库commit id中,checkout部分也没有。因为github仓库的commits记录是按分支分类的,没必要把本地切换分支的记录也写上去,要写也不知道写哪去。
github仓库的commit记录是push上去的记录,而且git commit -m "XX"
只能使用两次,再使用一次会不成功并提示要git push
一下:1
2
3
4
5
6
7
8
9
10
11zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git commit -m "delete 111.cpp"
On branch hzh11
Your branch is ahead of 'origin/hzh11' by 2 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: 111.cpp
no changes added to commit (use "git add" and/or "git commit -a")这里告诉你已经有两个commits了,不能再多了,要想再commit就要先push一下,下面部分就是你没commit成功所以有这些东西没有存。
branch
(在本地)创建新分支的命令是
git checkout -b branchname
。
创建分支是从当前HEAD中继承出来的(内容继承自当前HEAD分支),但是只是有个趋势,不会创建一个新的节点,用git log
命令可以发现什么都没发生,但是用git reflog
命令,会出现一个新记录。创建新分支,会创完并跳转到这个分支:
1
2zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git checkout -b branch1
Switched to a new branch 'branch1'
注意暂存区和分支没有关系,跟分支是独立的。不管哪个分支都共用了一个暂存区,commit的时候,会看你当前在哪个分支,就把暂存区内容加到哪个分支的后面。切换分支的时候,不会有多个暂存区,不管在哪个分支上都用了一个暂存区和工作目录。
- git branch 命令:
分支操作 命令 创建分支 git branch <name>
:创建叫name的分支,但仍然停留在当前分支。git checkout -b <name>
:创建叫name的分支,并切换到name分支。删除分支 git branch -d <name>
:参数为-D则为强制删除,这个命令是删除本地分支。git push origin --delete <name>
:删除远程仓库的叫name的分支,同名的本地分支并不会被删除,所以还需要单独删除本地同名分支。git branch -dr <remote>/<branch-name>
:没有删除远程分支,只是删除git branch -r
列表中的追踪分支。一般只有git push
命令可以修改远程仓库。创建+切换分支 git switch <name>
:只能用来切换到已有的分支,不能用来创建新的分支。git checkout <name>
:只能用来切换到已有的分支,不能用来创建新的分支。git branch <name>
:只能用来创建新分支,不能用来切换分支。创建但不会切换到新分支。git switch -c <name>
:只能用来创建新分支,不能用来切换分支。创建但切换到新分支。查看分支 git branch
:查看本地分支,当前分支前面会标一个*号。git branch -r
:查看远程分支和本地分支的关联。git branch -a
:查看本地分支和本地分支与远程分支的关联,本地分支与远程分支的关联会用红色表示出来(如果你开了颜色支持的话)。git branch -v
:查看每个分支的最新版本和版本号。git branch -vv
:类似于git branch -v
,区别在于会有蓝色提示,类似于[origin/branch_name]
,表示最新commit的修改在这个分支。重命名分支 git branch -m oldName newName
操作远程分支 git push --set-upstream origin branch_name
:设置本地的branch_name
分支对应远程仓库的branch_name
分支。git push -u origin/remote_branch_name
:将本地新建的分支与远程分支相关联,同上。git branch --unset-upstream
:撤销当前本地分支和其远程分支的关联。git push -d origin branch_name
:删除远程仓库的branch_name
分支。git push origin branch_name
:将本地的某个分支推送到远程仓库。git merge branch_name
:将分支branch_name合并到当前分支上
如果无冲突就是fast-forward合并了。
如果有冲突,比如在同一个文件上,两个分支的内容不一样,就会提示合并不成功(但是你当前所在的文件会出现一些“》》》》》》”类的东西),请手动合并后再持久化:1
2
3
4zstueto@LAPTOP-QJGKA05C:/mnt/d/Internet$ git merge test1
CONFLICT (add/add): Merge conflict in 1.cpp
Auto-merging 1.cpp
Automatic merge failed; fix conflicts and then commit the result.对于有冲突的文件,打开,用vsc的合并编辑器或者linux终端的vim或者纯手动修改后,commit一下就行。
另外,若想禁用fast-forward模式,用–no-ff,这个有需求的时候自己可以临时查。git用远程分支代码强制覆盖本地分支代码:
1
2
3git fetch --all
git reset --hard origin/master
git pullgit用本地代码强制覆盖远程代码:
1
git push origin branch_name -f
栈空间
git stash
用来:
有时,当你在项目的一部分上已经工作一段时间后,所有东西都进入了混乱的状态, 而这时你想要切换到另一个分支做一点别的事情。 问题是,你不想仅仅因为过会儿回到这一点而为做了一半的工作创建一次提交。 针对这个问题的答案是git stash
命令。git stash
:将工作区和暂存区中尚未提交的修改存入栈中git stash apply
:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素git stash drop
:删除栈顶存储的修改git stash pop
:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素git stash list
:查看栈中所有元素
可以看这个教程 Git 工具 - 贮藏与清理