动机
久仰Git
版本管理的大名,自己在做一些项目时也发现版本的管理是个头疼的问题。因此作为一项硬技能,有必要好好学一下。
Git原理
首先理解一下工作区、版本库的概念。
- 工作区:仓库目录下除
.git
之外的,用户进行一系列新建、修改文件的区域。 - 版本库:仓库目录下的一个(隐藏)目录
.git
,这个就是Git的版本库。- 版本库中有暂存区(
stage
或index
)、(自动创建的)master
分支和指向该分支的指针HEAD
。
- 版本库中有暂存区(
创建版本库
在目标目录下执行git init
,把目标目录变为Git
可以管理的仓库。执行后便可发现当前目录自动生成了一个.git
目录,这个目录是Git
来跟踪管理版本库的。
没事不要手动修改这个目录里面的文件,不然改乱了,就把
Git
仓库给破坏了。
执行git add <file>
,把文件添加到暂存区。
执行git commit -m "message"
,把暂存区的文件提交。-m
后面输入的是本次提交的说明,当需要查看历史记录时显示的就是这个说明,所以要写得有意义些,便于区分。
可以一次add许多文件到缓存区,如
git add file1.txt, file2.txt
,然后一次性commit提交到仓库中。
git add .
:add所有文件的所有变化,在Git 2.x中与git add -A
等效(在Git 1.x中不等效,区别在于git add .
不包含文件删除操作,可参见Stackoverflow)
几个重要且常用的命令
-
git status
:查看当前仓库状态信息。 -
git ls-files
:列出Git
跟踪了哪些内容。 -
git rm --cached <file>
:如果一些文件已经被track了,但实际上并不想track,可以使用该命令将其移去。参考
使用.gitignore
文件
.gitignore
为一纯文本文件,显式地告诉Git
哪些文件不要被track,可参见bmcblog。一个文件示例如下:
1
2
3
4
5
6
7
# Binaries for programs and plugins
*.exe
*.dll
*.so
# Dependency directories
vendor/
版本管理
撤销在暂存区的内容
已经执行了git add
把文件加到了暂存区,但是想撤销这次操作,可使用:参考
1
git reset
回退版本
该操作把分支内容直接回退回老版本。
Git
版本回退一般有两种方式:
- 使用
HEAD
标识。在Git
中,用HEAD
表示上一次commit后的版本1
git reset --hard HEAD
- 使用
commit id
。git log
和git reflog
可获取历史版本的commit id
,使用1
git reset --hard <commit id>
可以恢复到对应的版本。
commit id
不用写全,一般写前面5位就可以了,Git会自动补全。使用
git reflog
查看commit id
git reset
只会回滚modified的文件,新增的文件在reset后仍存在。
几个重要且常用的命令
-
git log
:查看历史修改记录。-
git log --pretty=oneline:
:历史记录简洁输出。 - 输出的前面一串数字是
commit id
(版本号),是标识commit版本的依据。 - 当回退到旧版本时,使用该命令将只会输出该旧版本之前的历史记录(像是时光穿梭到了旧版本对应的时刻),如果想要查看包含以往每一次的操作,可使用下面的这条
git reflog
命令。
-
-
git reflog
:查看使用过的每一次命令以及对应的版本号。
分支管理
Git分支原理
Git把每次的提交串成一条时间线,一条时间线就是一个分支,分支间的切换实质上是HEAD
指向的切换。详见廖雪峰-创建与合并分支。Git中鼓励大量使用分支。
创建与切换分支
- 创建分支:
git branch <branch_name>
- 切换至分支:
git checkout <branch_name>
或git switch <branch_name>
- 创建并切换至该分支(等效与上述两条命令):
git branch -b <branch_name>
或git switch -c <branch_name>
- 查看当前所有分支:
git branch
- 当前分支前会标有星号。
合并分支
使用git merge <branch_A>
将指定分支branch_A
合并到当前分支上。默认合并模式是Fast-forward
模式。Fast-foward
模式可以无痛作用于在一个分支上进行单线延伸后的合并。

- 如果执行了fast forward,开发者根本看不到被合并的分支,就像在
master
上直接commit一样(参考-segmentfault)。- 合并分支时,加上
--no-ff
参数就可以用普通模式合并,即git merge --no-ff <branch_A>
合并过程中的冲突解决
当从同一节点分叉出的两个分支分别在同一位置做了不同的修改,那么直接git merge
将提示存在文件出现冲突。此时必须手动解决冲突后再提交,具体操作为:
- 直接在本地打开提示冲突的文件,在发生冲突的地方进行编辑,解决冲突;
git merge
的合并冲突结果会直接反映在工作区,也就是说在工作区冲突文件对应位置处增加了显式的提示,具体格式为:用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,比如1 2 3 4 5
<<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1
- 进行正常的提交操作,即依次进行
git add
和git commit
即可。
删除分支
使用git branch -d <branch_name>
删除指定分支。
分支管理策略
实际开发中,应该按照几个基本原则进行分支管理:
-
master
分支应该是非常稳定的,始终拥有(存档)着最稳健的版本; -
dev
分支是不稳定的,有了稳定的功能后再合并到master
分支上; - 团队合作时,每个人都在
dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并。
“修改操作”的复制
想象一个场景,master
分支上有一个bug
,于是在master
分支上创建临时分支issue-101
,然后在issue-101
分支上修复后提交(对应<commit_id>
),然后将切换到master
分支,将issue-101
分支合并。master
分支上的bug
修复了,但是因为dev
分支是从早期master
分支分出来的,所以也存在这个bug
,这个时候可以切换到dev
分支,执行
1
git cherry-pick <commit_id>
将issue-101
在<commit_id>
对应的那次提交里所作的“修改操作”复制到dev
分支上。dev
分支上的那个bug
也就被解决了。
这里有一个可视化交互的
Git
分支教程,挺有意思。
标签管理
创建标签
Git
的标签(tag
)实际上就是一个指向某个commit
的指针,与commit_id
作用实际上是一样的,但是更适合人类记忆。另外,对应里程碑性的提交,也可以特意为其打上一个tag
。打tag
的方法为
1
git tag <tag_name>
默认tag
是打在最新提交的commit上的。如果想要为某一个commit_id
打上tag
,可以
1
git tag <tag_name> <commit_id>
查看标签
使用git tag
查看当前所有标签。标签不是按时间顺序列出,而是按字母排序的。 使用git show <tag_name>
查看标签信息(该标签对应的commit_id
、提交作者、日期、所作的修改等)。
操作标签
使用git tag -d <tag_name>
删除标签。 使用git push origin <tag_name>
将标签对应的提交推送到远程。
远程仓库
初次使用
Windows
初次使用自己的远程仓库需要创建SSH key来在github上进行Git仓库托管。 (注:Windows下主目录为C:\Users\用户名\
)
Ubuntu
同样需要创建SSH key来在github上进行Git仓库托管。 (注: Ubuntu的ssh
文件在~/.ssh
)
添加远程库
当先有本地仓库,希望同步到远程仓库时:
- 在github上新建一个远程仓库;
- 把本地仓库和远程仓库关联;
1
git remote add origin git@github.com:<account_name>/<repo_name>.git
这里的
origin
是设定的远程库的名字,后面跟的是仓库的地址。origin
是Git
默认的叫法,也可以改为其他名字。 - 把本地库的所有内容推送到远程库。
1
git push -u origin master
即将本地
master
分支的内容推送到远程库origin
的master
分支上(在本地master
分支推送就推到远程的master
分支上,在本地dev
分支推送就对应推送到远程的dev
分支上)。由于初次提交时,远程库是空的,这里还加了参数-u
,它把本地的master分支和远程的master分支关联起来(注意这里有一个本地分支和远程分支的关联问题,后面会提到多次),简化后续推送的命令。在以后的推送,只需1
git push origin master
克隆远程仓库
当已有远程仓库,希望克隆到本地时:
1
git clone <repo_addr>
当从远程仓库克隆时,在下载文件的同时,也自动把本地的master
分支和远程的master
分支关联起来了,并且,远程仓库的默认名称是origin
。
github为仓库提供了多个地址(https
协议、ssh
协议),不过优先选用ssh协议,速度更快而且方便。比如
1
git clone git@github.com:ZhangGe6/onnx-modifier.git
- 可能遇到的问题:fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
- 解决:检查本地电脑是否已经创建SSH key(新电脑有时会忘记)。
远程克隆别人的仓库时,默认只能看到master
分支,如果需要看到其他分支,比如dev
分支时,则需要
1
git checkout -b dev origin/dev
远程分支管理
查看远程库的信息:
使用git remote
查看远程库的信息, 加上-v
参数可以显示更详细的信息,即pull
和push
的权限。
1
2
3
4
5
$ git remote
origin
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
推送分支
推送分支,就是把指定分支上的所有本地提交推送到远程库,使用
1
git push origin <branch_name>
即将<branch_name>
指定的分支推送到远程对应分支。
注:实际推送哪个分支与当前在哪个分支无关。也就是说,即便当前处于
dev
分支,执行git push origin master
会把本地的master
分支推送到远程master
分支,而不是远程dev
分支云云。
抓取分支
抓取分支,就是把远程库中的(当前工作区所在分支在远程库中关联的)分支直接抓取下来到工作区,使用
1
git pull
如果出现
1
2
3
4
There is no tracking information for the current branch.
...
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> <cur_local_branch>
则按照提示执行
1
git branch --set-upstream-to=origin/<remote_branch> <cur_local_branch>
即将远程库中的remote_branch
分支和本地cur_local_branch
关联起来,以后在cur_local_branch
下执行git pull
操作时都会从关联的remote_branch
进行抓取。
冲突解决
推送冲突解决
当两次push
发生冲突(比如两次push
在对应同一个位置做了不同的修改)时,则需要把上一次的推送pull
下来,在本地解决冲突后,重新push
上去。
抓取冲突解决
抓取冲突的解决,实质上就是本地的冲突解决了。在对应冲突的地方做好增删保留即可。
协作:
致谢
以上内容根据廖雪峰老师的Git教程总结摘取而来。廖雪峰老师的这份教程使用具体实例,深入浅出地讲解了常用的Git
的原理和常用操作,非常适合初学者,跟着实际操作一番后收获颇丰。感谢廖老师的工作!
其他操作
以下是一些平时使用中积累的其他操作。
Git 版本升级(至最新版本)
- 查看当前
Git
版本:git --version
- 升级
Git
版本:- 添加源:
sudo add-apt-repository ppa:git-core/ppa
- 更新安装列表:
sudo apt-get update
- 升级
Git
:sudo apt-get install git
- 添加源:
Partial Clone
使用Github镜像Gitee
亲测clone那真是快得不是一点两点..
Git状态码
-
M
: modified -
A
: added -
D
: deleted -
R
: renamed -
C
: copied -
U
: updated but unmerged
Git从历史记录中删除大文件和查看文件大小
查看个人在github的所有comment
点击这个神奇的链接: https://github.com/notifications/subscriptions?reason=comment
trouble shoot
ssh: Could not resolve hostname github.com: Name or service not known
1
ssh -T git@github.com