Git学习笔记
Git学习笔记 by 《ProGit》
Git设计理念
Git直接记录快照,而非差异比较
基于差异**(Delta-based)** , 像CSV、Subversion、Perforce。它们如何建立新版本:在版本1的基础上,建立一个记录
版本2(新版本)
与版本1
差异的文件,我们称其为$\Delta1$ .当我们需要读取版本2时,可以通过**$版本1 + \Delta1$** 计算得出版本2。Git快照流,提交后,建立一个新的快照:对修改过的文件建立一个新的快照并保存其索引,对未修改的文件并不重新存储,而是只保留一个链接指向旧文件


Git 基础
Git工作状态
三种状态:已提交(committed)
、已修改(modified)
、已暂存(staged)
, 对应三个阶段:工作区
、暂存区
、Git目录(仓库)
。


Git配置
安装Git后添加用户信息:
1 | git config --global user.name "benkangpeng" |
1 | cd /c/user/my_project |
Git基本操作
获取mannul
1 | git <verb> -h |
ex : git add -h
git init
1 | cd /my_project/ |
初始化Git仓库,此时会在my_project文件夹中生成.git
子目录用于存放版本控制文件。注意:此时还没对项目文件进行跟踪 , 还需要git add
跟踪所需文件。
git add
1 | git *.c # 跟踪所有后缀为.c文件 |
git add
内涵:
要暂存这次更新,需要运行 git add
命令。 这是个多功能命令:①可以用它开始跟踪新文件,②或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。
git status
显示当前文件夹git状况。
On branch master
No commits yet
Changes to be committed:
(use “git rm –cached…” to unstage)
new file: README.mdUntracked files:
(use “git add…” to include in what will be committed)
CONTRIBUTING.md
如上显示的是,README.md
已被跟踪,而CONTRIBUTING.md
未被跟踪。
1 | git add CONTRIBUTING.md |
On branch master
No commits yet
Changes to be committed:
(use “git rm –cached…” to unstage)
new file: CONTRIBUTING.md
new file: README.mdChanges not staged for commit:
(use “git add…” to update what will be committed)
(use “git restore…” to discard changes in working directory)
modified: README.md
- 此时
CONTRIBUTING.md
已经被跟踪 - 提示有
待提交的修改
(changes to be committed) ,CONTRIBUTING.md
和README.md
没有提交。(至于changes , 即new file
, git将创立文件
也视为changes
) Changes not staged for commit
: 我们刚才向README,md
写入了My project
, 但没有将新版本的README.md
添加进入暂存区stage
。可执行操作git add README.md
- 上面这条再一次体现了
git add
的双重命令,或将其理解为为文件提交(commit)做好预备
.gitignore
创建.gitignore
文件忽略追踪
1 | touch .gitignore |
常见语法:
1 | # 忽略所有的 .a 文件 |
git diff
git diff
查看同一文件已暂存
与未暂存
的两个版本的差异eg. 在
README.md
中添加一行哈哈
,no stage , 使用命令查看:
$ git diff README.md
diff –git a/README.md b/README.md
index 6fcadd0..b2f8c83 100644
— a/README.md
+++ b/README.md
@@ -1 +1,3 @@
My project~
+
+哈哈
\ No newline at end of file
git diff --staged
查看已暂存文件
与最后一次提交文件
的差异.
1 | git diff --staged README.md |
git commit
每次准备提交前,先用 git status
看下,你所需要的文件是不是都已暂存起来了, 然后再运行提交命令 git commit
:
1 | git commit -m "the first commit" |
-m
: 添加提交信息message“the first commit” : 提交的信息,区分每一次提交做了哪些大体的修改
git commit -a
跳过暂存区,直接将为暂存的文件commit .
git rm
- 如果你想从磁盘根本删除
未暂存的文件
:
1 | git rm PROJECT.md |
- 从暂存区删除(取消跟踪)文件(仍保存在磁盘里):
1 | git rm -f PROJECT.md #-force , 强制删除 |
git mv
git mv
移动文件 or 重命名文件。
1 | git mv Project.md PROJECT.md |
上述命令相当于:
1 | mv Project.md PROJECT.md |
git log
git log
显示所有提交日志git log -2
显示最近两条日志git log -p
按补丁格式显示每个提交引入的差异git log --pretty=oneline
显示格式为一行- 此外还有一些参数过滤日志内容,例如
--since``--author
等,可查文档。
git commit –amend
- 提交后发现上一次提交有些许瑕疵,例如message写错了、没有跟踪上某个文件 ,但又不想再一次提交,想覆盖上一次提交。
1 | git commit --amend -m "the right message" |
git reset
- 强制重置(删除)某个commit, 例如
git reset --hard HEAD~1
删除上一次提交。 - 取消暂存的文件,例如将
CONTRIBUTING.md
文件取出``stageing area,
git reset HEAD CONTRIBUTING.md`
git rebase
git rebase
命令是用于解决开发者仓库与上游upstream
仓库之间同步问题的命令。

以TVM
为例,你fork
完tvm后,提交了两个commit,在此期间,tvm upstream又更新了两个commit,这时如何将你的commit贡献给上游呢?
1 | git fetch upstream #将上游仓库更新到本地,但不合并(与git pull不同) |
git rebase
的工作流程:
如果git rebase
发生冲突,则需要手动解决冲突,并:
1 | git add <conflicit file> |
*文件版本回溯
案例:commit log
如下,自从git clone
以来,我提交了version 1
和version2
.整个项目只有两个文件:check.md
和README.md
. 我现在想将check.md
还原到version 1
的状态,但README.md
不用还原。(可以理解为我后知后觉意识到version2
中对check.md
的修改是错误的。)
$ git log –pretty=oneline
bc03ee1185c084b514ff44a9520ab5d29777b600 (HEAD) version2
3d44a28a78ffba2eab8d0718e34c3f7463cfa2a1 version 1
86d413d821c361c0245859fddd9c6258f698f16f (tag: v1.0, origin/main, origin/HEAD) colle
ct some ways to github
1bfa40c95f5b2a5a086421889e60321ef056fbc0 (tag: v0.1) the first commit by git push
a41ee579c6756e653d380b2e08426ea74f77841d (tag: v0.0) Create README.md
1 | git reset 3d44a # 3d44a是version1的效验码,没写完整 |
但以上做法删除了version2的提交信息。是否存在方法,只进行单个文件的版本回溯呢?现在还没解决……
*单文件版本回溯
1 | git log --pretty=oneline |
- 将
check.md
回溯到版本1,其他文件不变,git checkout <hash> check.md
1 | git checkout 3d44a28a check.md |
与远程仓库联动
git remote add <name> <url>
添加远程仓库,例如git remote add getback https://github.com/BenkangPeng/GetBack.git
, 之后可用名称getback
代替网址进行操作。类似于C
里的#define
git remote -v
显示已添加的远程仓库,git remote
简略显示。git remote rename name1 name2
修改仓库代称,实际远程仓库(比如Github上的仓库)名称没被修改。
1 | git remote add getback https://github.com/BenkangPeng/GetBack.git |
git fetch
获取仓库的更新。例如,你在1年以前clone
了仓库A
, 但在过去一年内,仓库A
其他开源贡献者提交了许多内容,甚至产生了分支,git fetch <url>
将仓库A
的这些更新数据下载到本地,但不会改变本地状态:不会自动合并分支或修改你当前的工作。当然你可以手动合并分支、更新本地仓库。git clone <url>
克隆仓库。将<url>
对应的仓库克隆到本地,与git fetch
不同的是,它将覆盖本地工作。
1 | git clone https://github.com/BenkangPeng/GetBack.git |
关于主分支
master
改为main
,还颇有意味。github/renaming 乐子 on 知乎
Tag
git tag -a <v1.0> -m "version 1.0"
添加annotated tag
,git tag v1.0
添加lightweight
标签。git tag
显示所有标签,git show <v1.0>
显示某个标签信息git tag <version> <verify code>
为之前某一次commit
补充tag
1 | git log --pretty=oneline |
- 默认情况下,
git push
不会顺带将每一个commit
的tag
提交,需手动设置。git push origin <tagname>
上传单个tag
,git push origin --tags
推送所有tags
git tag -d <tagname>
删除标签,但不会删除远程仓库(``remote)的
tags, 需用
git push origin –delete`
Git分支
1 | git branch testing #创立分支testing |
git merge <branch>
1 | git touch polynorminal.cpp |
在main
中合并分支时,可能出现合并冲突,这是因为分支中文件修改过大,git
不知道如何将main
与branch
两个文件版本合并,此时需手动合并、修改文件,并commit
git branch -d <branch>
删除分支(但不能删除未合并的分支)git branch --no-merged
查看未合并的分支
Git版本回溯(by branch)
我一直是用git reset --hard <hash_id>
进行版本回溯,但这样会丢失之后的commit,导致版本混乱。现在想到一个方法,可以用分支来进行回溯查看。(当然,如果我们确定要回到某个commit重新工作,并确定要丢失之后的commit,也可以硬重置。)
查看当前分支
1 | git log --oneline --decorate --graph --all |
现在我们正在sparse
分支上,因为改动较大,想回到稠密版本上查看稠密版本的源码:
1 | git checkout -b check_dense_version e339fae |
这时整个工作目录的文件都变成了e3319fae
时的版本。在这个版本下,如果我们运行代码导致一些文件发生了修改,工作目录不干净,是不能直接switch
回sparse
的:
1 | git switch sparse |
提示显示如果我们要更换分支,需要commit
或者stash
- 如果我们不需要提交,可以将文件变更取消掉,再
switch
1 | git restore . #将所有被修改的文件复原 |
git stash
如果我们在sparse
分支下工作目录有修改未提交,那么切换分支之前需要将修改存入stash
。
1 | git log --oneline --decorate --graph --all |
git stash相关命令
git stash save [message]
:将当前工作目录的修改保存到一个stash列表中,并附带一条可选的描述信息。git stash list
:列出所有的stash列表。git stash apply [stash_id]
:将指定的stash应用到当前工作目录,但不从stash列表中删除。git stash pop [stash_id]
:将指定的stash应用到当前工作目录,并从stash列表中删除。git stash drop [stash_id]
:从stash列表中删除指定的stash。git stash branch [branch_name] [stash_id]
:基于指定的stash创建一个新的分支,并将stash应用到新分支上。git stash pop --index [stash_id]
:将指定的stash应用到当前工作目录和索引(暂存区),并从stash列表中删除