Home Git学习
Post
Cancel

Git学习

动机

久仰Git版本管理的大名,自己在做一些项目时也发现版本的管理是个头疼的问题。因此作为一项硬技能,有必要好好学一下。

Git原理

首先理解一下工作区、版本库的概念。

  • 工作区:仓库目录下除.git之外的,用户进行一系列新建、修改文件的区域。
  • 版本库:仓库目录下的一个(隐藏)目录.git,这个就是Git的版本库。
    • 版本库中有暂存区(stageindex)、(自动创建的)master分支和指向该分支的指针HEAD在这里插入图片描述
Git的工作区与版本库

创建版本库

在目标目录下执行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版本回退一般有两种方式:

  1. 使用HEAD标识。在Git中,用HEAD表示上一次commit后的版本
    1
    
     git reset --hard HEAD
    
  2. 使用commit idgit loggit 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

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 和 no fast foward合并模式区别
  • 如果执行了fast forward,开发者根本看不到被合并的分支,就像在master上直接commit一样(参考-segmentfault)。
  • 合并分支时,加上--no-ff参数就可以用普通模式合并,即git merge --no-ff <branch_A>

合并过程中的冲突解决

当从同一节点分叉出的两个分支分别在同一位置做了不同的修改,那么直接git merge将提示存在文件出现冲突。此时必须手动解决冲突后再提交,具体操作为:

  1. 直接在本地打开提示冲突的文件,在发生冲突的地方进行编辑,解决冲突;

    git merge的合并冲突结果会直接反映在工作区,也就是说在工作区冲突文件对应位置处增加了显式的提示,具体格式为:用<<<<<<<=======>>>>>>>标记出不同分支的内容,比如

    1
    2
    3
    4
    5
    
     <<<<<<< HEAD
     Creating a new branch is quick & simple.
     =======
     Creating a new branch is quick AND simple.
     >>>>>>> feature1
    
  2. 进行正常的提交操作,即依次进行git addgit commit即可。

删除分支

使用git branch -d <branch_name>删除指定分支。

分支管理策略

实际开发中,应该按照几个基本原则进行分支管理:

  1. master分支应该是非常稳定的,始终拥有(存档)着最稳健的版本;
  2. dev分支是不稳定的,有了稳定的功能后再合并到master分支上;
  3. 团队合作时,每个人都在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也就被解决了。

:satisfied: 这里有一个可视化交互的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)

在这里插入图片描述

Git操作原理图

添加远程库

当先有本地仓库,希望同步到远程仓库时:

  1. 在github上新建一个远程仓库;
  2. 把本地仓库和远程仓库关联;
    1
    
     git remote add origin git@github.com:<account_name>/<repo_name>.git
    

    这里的origin是设定的远程库的名字,后面跟的是仓库的地址。originGit默认的叫法,也可以改为其他名字。

  3. 把本地库的所有内容推送到远程库。
    1
    
     git push -u origin master
    

    即将本地master分支的内容推送到远程库originmaster分支上(在本地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参数可以显示更详细的信息,即pullpush的权限。

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
    • 升级Gitsudo apt-get install git

Partial Clone

参考

使用Github镜像Gitee

廖雪峰的官方网站-使用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

参考

This post is licensed under CC BY 4.0 by the author.

Ubuntu基础操作

VS code使用