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 *git add .的区别

几个重要且常用的命令

  • git status:查看当前仓库状态信息。
  • git diff <file>:查看当前工作区<file>相对于暂存区版本修改了什么内容。

使用.gitignore文件

版本管理

撤销工作区修改

该操作使用暂存区的内容替换工作区的内容,对应命令为

git checkout -- <file>

撤销暂存区修改

该操作使用已提交内容替换暂存区的内容,对应命令为

git reset HEAD <file>

分支版本回退

该操作把分支内容直接回退回老版本。

Git版本回退一般有两种方式:

  1. 使用HEAD标识。在Git中,用HEAD表示当前版本,HEAD^表示上一版本,HEAD^^表示上上一版本…那么想由当前版本回退到上一版本,可使用
    git reset --hard HEAD^
    
  2. 使用commit idgit loggit reflog可获取历史版本的commit id,使用
    git reset --hard <commit id>
    

可以恢复到对应的版本。commit id不用写全,一般写前面5位就可以了,Git会自动补全。

注: 上述三个操作对应同一个链条上不同的环节,三个操作之间相互独立,执行一个操作不会影响其他操作对应的环节。比如分支版本回退操作里,只是将HEAD指向的分支版本做了回退,而不会影响暂存区和工作区内容,若要将版本回退反映到工作区,则需要继续依次执行撤销暂存区修改、撤销工作区修改操作。

删除文件

一个观念:在Git中,删除和增加一样,都被视为一个修改操作。

当在工作区删除了某一文件,即rm file

如果想从暂存区和分支中均删掉该文件,则须依次执行

git rm <file>     #从暂存区删除该文件(和 git add 命令对应)。
git commit -m "delete file"     #将暂存区修改提交到分支上,加上提交说明。

而如果是在工作区误删了文件,则只需像上面说的,执行git checkout -- file把暂存区内容拉回到工作区就可以了。

几个重要且常用的命令

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

     <<<<<<< 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分支,执行

git cherry-pick <commit_id>

issue-101<commit_id>对应的那次提交里所作的“修改操作”复制到dev分支上。dev分支上的那个bug也就被解决了。

标签管理

创建标签

Git的标签(tag)实际上就是一个指向某个commit的指针,与commit_id作用实际上是一样的,但是更适合人类记忆。另外,对应里程碑性的提交,也可以特意为其打上一个tag。打tag的方法为

git tag <tag_name>

默认tag是打在最新提交的commit上的。如果想要为某一个commit_id打上tag,可以

git tag <tag_name> <commit_id>

如果想要创建一个带有说明的tag,则可以

git tag -a <tag_name> -m 'message'

效果与git commit -m "messge"写好说明提交后再使用git tag <tag_name> <commit_id>tag打到该提交上是等效的。

查看标签

使用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)

如果出现

Agent admitted failure to sign using the key.
...
Permission denied (publickey)
...

则可以使用ssh-add指令将私钥加进来

ssh-add   ~/.ssh/id_rsa

在这里插入图片描述

添加远程库

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

  1. 在github上新建一个远程仓库;

  2. 把本地仓库和远程仓库关联;

    git remote add origin git@github.com:<account_name>/<repo_name>.git
    

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

  3. 把本地库的所有内容推送到远程库。

    git push -u origin master
    

    即将本地master分支的内容推送到远程库originmaster分支上(在本地master分支推送就推到远程的master分支上,在本地dev分支推送就对应推送到远程的dev分支上)。由于初次提交时,远程库是空的,这里还加了参数-u,它把本地的master分支和远程的master分支关联起来(注意这里有一个本地分支和远程分支的关联问题,后面会提到多次),简化后续推送的命令。在以后的推送,只需

    git push origin master
    

克隆远程仓库

当已有远程仓库,希望克隆到本地时:

git clone <repo_addr>

当从远程仓库克隆时,在下载文件的同时,也自动把本地的master分支和远程的master分支关联起来了,并且,远程仓库的默认名称是origin

github为仓库提供了多个地址(https协议、ssh协议),不过优先选用ssh协议,速度更快而且方便。比如

git clone git@github.com:ZhangGe6/sports_counting_by_pose_estimation.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分支时,则需要

git checkout -b dev origin/dev

远程分支管理

查看远程库的信息:

使用git remote查看远程库的信息, 加上-v参数可以显示更详细的信息,即pullpush的权限。

$ git remote
origin
$ git remote -v
origin  git@github.com:michaelliao/learngit.git (fetch)
origin  git@github.com:michaelliao/learngit.git (push)

推送分支

推送分支,就是把指定分支上的所有本地提交推送到远程库,使用

git push origin <branch_name>

即将<branch_name>指定的分支推送到远程对应分支。

注:实际推送哪个分支与当前在哪个分支无关。也就是说,即便当前处于dev分支,执行git push origin master会把本地的master分支推送到远程master分支,而不是远程dev分支云云。

抓取分支

抓取分支,就是把远程库中的(当前工作区所在分支在远程库中关联的)分支直接抓取下来到工作区,使用

git pull

如果出现

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>

则按照提示执行

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那真是快得不是一点两点…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值