本文主要介绍git的版本库,分支,远程仓库相关的概念和相关的操作指令,主要是为了记录自己的学习过程,加深自己的理解和便于日后检索,很多的细节没有深入解释和说明,如果你没有git使用经历和基础,则不适合阅读本文

背景

在日常开发过程中,我们常常需要使用git对代码进行版本管理,git帮助我们跟踪代码的变动,记录版本的更迭,正确有效地使用git,能够极大地提高我们的开发效率,并且可以很方便地进行团队开发,本文主要介绍的是git的一些基础概念,比如git如何跟踪记录代码的变化,什么是版本号,git的工作区(working copy),暂存区(index),和HEAD区,分支的概念,以及远程仓库的概念。在介绍这些概念的同时,也列出需要使用到的git指令,以供参考使用

一、版本库

1.1 什么是版本库?

git使用版本库来跟踪代码的变化,每次的提交(commit)使用一个版本号来记录,也就是commit id,由于git是分布 式的版本管理系统,因此,为了使得这个版本号具有全局的唯一性,并不使用简单的数字递增的形式来记录,而是使用了安全哈希算法(SHA),从已有的数据中产生一个消息摘要(也就是一个字符串),不同的提交有不同元数据信息,因此几乎不可能产生重复的哈希码,也就能使得commit id具有全局的唯一性。

在使用git的时候,需要在一个目录中建立一个git仓库(也就是一个隐藏的.git文件夹),这个目录就是这个仓库的工作目录,也叫工作区,如果我们需要对某个文件进行版本管理,首先需要将文件添加到版本管理中(提交到暂存区使用的是git add指令,后面介绍),此后我们就可以将修改提交到版本库中,让git替我们跟踪记录文件的变化,不过,我们并不是直接文件的修改提交到分支中(分支的概念将在下文介绍),而是先将修改提交到暂存区,然后在一些合适的时机,一次性将暂存区的所有修改提交到分支上来(提交到分支使用的是git commit指令,后面介绍),不过需要注意的是,这里只提交了暂存区中的修改,并没有提交工作区的修改,工作区的修改需要add到暂存区才能提交到分支中)

1.2 提交相关的指令

git add 的三种姿势
  • git add <文件名> 将该文件的修改提交到暂存区
  • git add <文件目录> 将该目录下的所有修改提交到暂存区
  • git add . 将当前目录下的所有修改提交到暂存区
git commit 的四种姿势
  • git commit 启动文本编辑器来编辑提交留言,通常用于需要书写很多行提交留言的场景
  • git commit -m "message" 提交并添加留言,其中双引号中的内容是提交留言
  • git commit -a 提交本地工作目录下的所有修改,并启动文本编辑器,这是一个快捷的指令,相当于使用git add+git commit
  • git commit -am "message" 作用和第三个相同,只是不启动文本编辑器
git checkout 恢复工作区文件
  • git checkout <文件名> 表示将工作区的文件恢复到暂存区的状态,这个指令还可以用于切换分支,后面介绍

二、版本管理

2.1 什么是版本管理?

在git中,不同时间点上的版本有不同版本号,使用版本号来唯一标识一个版本,并且使用一个HEAD指针来指向当前的版本,我们可以使用版本号来切换到不同的版本上(也就是改变HEAD的指向),下面是使用文字和符号来代替那串哈希码版本号的方式

  • HEAD 当前版本
  • HEAD^ 上一个版本
  • HEAD~n 上n个版本

2.2 版本管理相关的指令

  • git reset --hard <版本号> 表示切换到这个版本号所指的版本,这个版本可以是当前版本之前,也可以是之后的版本,这里的版本号可以是那个版本的哈希码,也可以使用上面的HEAD^等符号方便地表示上一个版本
  • git log 查看提交的历史,这个指令可以列出各个历史版本和他们的版本号
  • git reflog 查看使用命令的历史,因为在退回到以前的版本后在git log中看不到未来的版本,因此使用这个命令来查看当时的命令,就可以知道未来版本的版本号
  • git diff <版本号> 查看该版本和当前版本的差异

2.3 git reset的三个参数soft,hard,mixed

  • soft 最轻微的回退,只重置HEAD在分支上所指的commit,不会修改暂存区和工作区
  • hard 重置HEAD所指的commit,并将暂存区和工作区都恢复到与HEAD相同的状态,这个操作将会修改工作区文件,当前所做的修改会被覆盖
  • mixed 上面两者的结合,重置HEAD所指的commit,并将暂存区恢复到和HEAD相同,但是不会修改工作区文件

三、分支

3.1 什么是分支?

git使用分支的概念以便更好更安全地分工合作和进行尝试,因为不同的分支是互不影响的,其中有一个主要的分支叫做master ,是整个项目的主干,在其他分支中做出修改,测试,确认之后再将修改合并到主分支master中来,这样的做法十分安全,团队中的每个人都可以创建一个分支用于开发,做出自己的修改,再将其合并到主分支上,但是合并时,有可能出现冲突,关于冲突的解决将在后面介绍。不同的分支其实只是不同的指针,他们指向不同的结点,因此在git中,创建分支,合并分支等等操作都非常快,因为整个过程只涉及了指针的移动,工作区的文件没有任何变化。

在一个版本库中,除了有一个主分支之外,还会有一个当前分支,即HEAD指针所指的分支,通常HEAD分支默认指向master分支,我们可以创建一个新的分支dev并将当前分支更改为dev,之后我们所做的提交操作都会提交到dev分支中,而master分支一直停留在切换分支时的位置,当我们将dev分支合并到master分支时,如果没有冲突,git将会直接把master的指针移动到dev所指的位置,可以看到,合并分支的过程只需要移动指针,所以非常快速。

3.2 与分支有关的指令

  • git branch 查看当前分支,git将列出所有分支,并且在当前分支前面标一个星号
  • git branch dev 表示创建一个名为dev的分支
  • git checkout dev 表示将当前分支切换为dev分支
  • git checkout -b dev 表示创建一个dev分支,并将当前分支切换为dev分支
  • git branch -d dev 表示删除dev分支
  • git branch -m <旧名称> <新名称> 表示重命名一个分支,如果-m 写成 -M,则会覆盖已有的同名分支
  • git merge dev 表示将dev分支合并到当前分支上

3.3 拉取远程仓库的其他分支

  • git fetch origin <远程分支名>

这个指令可以把远程仓库origin上的这个分支拉取到本地,然后才可以对这个分支进行pull,push,merge等操作(见下面的关联远程分支)。

3.4 关联远程仓库的其他分支

  • git branch --set-upstream-to=origin/<远程分支名> <本地分支名>

拉去下来的远程分支需要先进行关联,才能进行推拉操作,如果没有关联,在推拉操作时会出现提示 :

There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> dev

此时只需要复制 git branch --set-upstream-to=origin/ dev 下来回车执行即可(git已经帮你填好了分支)

3.5 出现一个不在任何分支的提交怎么办?

此时应该使用这个提交的commit id创建一个新的临时分支,然后把这个新分支merge到当前分支上来,就可以把这个提交拉取到当前分支了,然后就可以删除那个临时的新分支
创建临时分支的指令如下:

  • git branch temp cbde65c

其中temp是临时分支的名称,可以任取,后面是那个提交的commit id

3.6 解决版本库冲突

问题:pull远程仓库时,出现Git refusing to merge unrelated histories on rebase,提示: fatal: unrelated_histories

解决方式:加上-allow-unrelated-histories

git pull origin master --allow-unrelated-histories
git merge origin origin/master
... add and commit here...
git push origin master

四、远程仓库

4.1 什么是远程仓库?

除了在本地建立git仓库之外,我们还需要用到远程仓库,也就是远程的版本库,以便我们将代码保存在远程的服务器上(比如github),或者与他人进行协作。

为了与远程仓库通信,git提供了三种进行通信的网络协议

  • SSH
  • git
  • HTTP/HTTPS

4.2 远程仓库相关的指令

  • git branch -r 列出所有的远程分支
  • git clone 克隆一个远程仓库
  • git fetch 更新远程分支,表示将远程仓库的修改更新到这个仓库的远程分支中,并不会将远程分支的内容合并到本地分支上
  • git pull <远程主机名> <分支名>:<本地分支名> 表示将远程仓库的某个分支取回合并到本地的一个分支上,相当于先使用git fetch 将远程的分支更新到这个仓库的远程分支,再使用git merge 将其合并到本地分支上
  • git push <远程主机名> <分支名>:<远程分支名> 表示将本地的某个分支推到远程仓库的一个分支上
  • git remote 列出已存在的远程分支
  • git remote add <别名> 添加一个远程仓库,并命名(默认的名称是origin)
  • git remote show <分支名> 显示一个远程分支的详细信息

4.3 冲突解决

在进行推拉操作或者合并操作时,可能会产生冲突,这是因为两个人同时对同一行代码进行了修改,但是前一个人在修改没有被pull到后一个人的本地仓库中来,我们在push之前应该先将远程库的分支pull下来,如果发生冲突,需要打开冲突所在文件,git会在产生冲突的地方标示出来,我们只需要删除git添加的标记,并选择留下一个版本的代码即可。

问题:

error: Merging is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.

解决:
打开git提示的产生冲突的文件,可以看到git标注出来的冲突的地方,git用一排等号分隔开冲突的两个版本,我们只需要根据需要留下一个版本,另外一个版本删除掉(包括<<<<<<HEAD这些标注的符号也删掉),就是解决了冲突,这时再merge就不会冲突了。

<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1

五、其他技巧

5.1 忽略某些路径的文件

使用.gitignore文件可以指定某些路径,以便git忽略这些文件,也就是git status时不会提示这些路径下面的文件的状态,并且无法添加这些路径下的文件到版本管理中。

使用方式:在git仓库的文件夹中创建一个.gitignore文件,打开这个文件填写需要忽略的路径即可。
比如:out/* 表示忽略out中的所有文件

六、总结

一天的学习内容大概就是这些,在和小组的人合作实践的过程中,遇到一些写权限的问题,原因是我在github上创建的仓库,别人clone之后只有读的权限,不能进行push的操作,需要在仓库设置中将他添加为协作者,才能进行推操作,除此之外,我们还有一些不规范的操作,比如直接将本地的master推到远程的dev分支等等,以下是导师指出的需要注意的问题

  • 本地分支应该与远程分支一一对应,比如本地master和远程master之间进行推拉操作,本地dev和远程dev之间进行推拉操作,而不要交叉进行
  • 本地的开发分支应该先测试完毕,解决冲突之后,再合并到master分支上
  • 在push之前应该先进行一次pull操作,以防止版本库冲突
Last modification:March 5th, 2020 at 01:01 pm
本文作者黄钰朝
文章标题Git学习笔记
本文链接https://hellochaos.cn/archives/2020/03/5.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
如果觉得我的文章对你有用,请随意赞赏