Git简明实用教程

Git 是什么

Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。(管理文件内容的版本,追踪内容的变化)

git是用于Linux内核开发的版本控制工具。与CVS、Subversion一类的集中式版本控制工具不同,它采用了分布式版本库的作法,不需要服务器端软件,就可以运作版本控制,使得源代码的发布和交流极其方便。git的速度很快,这对于诸如Linux内核这样的大项目来说自然很重要。git最为出色的是它的合并追踪(merge tracing)能力。

其组成的库目录包括:

  • hooks:存储钩子的文件夹
  • logs:存储日志的文件夹
  • refs:存储指向各个分支的指针(SHA-1标识)文件
  • objects:存放git对象
  • config:存放各种设置文档
  • HEAD:指向当前所在分支的指针文件路径,一般指向refs下的某文件

Git还包括一些常用的对象形式:

  • tree: 对象对应于文件目录。包含文件名列表以及文件的类型比特(包含许可权)、到blob(对应于文件)或tree对象的引用。

  • commit: 对象链接tree对象在一起而成为history,包含顶层源目录的tree对象名字、一个时间戳、log信息、0个或多个父commit对象的名字。用于保存特定版本的树型文件夹结构以及提交作者,电子邮件地址,日期和描述性提交消息。

  • tag: 对象是一个容器,包含了到另一个对象的引用,也可以增加关于另外对象的元数据。通常它保存需要追溯的特定版本数据的一个commit对象的数字签名。

Git还有一些常用的引用类型:

  • heads: 引用一个本地对象,是commit的指针。每个head可以指任意一个这样的指针。可以包含任意数量的heads。而”HEAD”(全部大写),仅仅指的是当前有效的head。默认情况下,在每个仓库下都有一个head,叫做master。

  • remotes: 引用远程repository中的一个对象

  • meta: 例如一个bare repository中的一个配置, 用户权限; refs/meta/config名字空间等

版本控制

Git 是一个版本控制工具,因此要使用其进行版本控制首先需要建立一个版本库

版本库

初始化版本库:

1
$ git init --bare

git 会作出以下回应:

1
Initialized empty Git repository in {{yourpath}}.git

该操作创建一个空的版本库,文件夹内目录结构如下:

其中包含了 confighead 两个对象。

HEAD 文件的内容如下:

ref: refs/heads/master 可以看到 HEAD 文件是一个索引文件,后面的地址指向了该索引的映射。目前该映射体现的是该版本仓库默认的分支,即 matser

向版本库中追加文件

假设项目管理文件夹包括以下部分:ProgramPartial

依据这两个文件夹及其内容建立版本内容,使用如下命令:

1
2
3
$ git add ./Program ./Partial

$ git update-index --add ./Program ./Partial

这样就向当前的版本分支中添加了两个文件夹:ProgramPartial

如果错误添加了某个文件夹或文件需要剔除出去可以使用如下命令:

1
2
3
$ git remove ./files

$ git update-index --force-remove ./files

git 会对5添加的文件或文件夹进行更改的跟踪。

可以使用纯文本文件 gitignore 来使得在向版本库添加文件时自动忽略这些文件。该文件放置在git的工作目录下,与文件夹 .git/ 同级。

该文件内容直接写入要忽略添加的规则,每行一个,支持文件名,文件夹,通配符和正则表达式。

将添加的文件提交到版本库

使用以下命令将添加的文件提交到版本库

1
2
3
4
5
$ git commit # 提交到版本库

$ git status # 查看版本库的状态

$ git commit -m 'description' # 该版本的描述

使用以下命令可以比较当前工作目录与版本库的差别:

1
$ gitdiff

管理分支

如果项目存在多个分支就需要进行分支管理:

1
$ git branch

使用以下命令创建分支并将创建的分支设置为当前工作分支:

1
2
3
4
$ git branch newB
$ $ git checkout newB
等价于
$ git checkout -b newB [start_point]

删除分支:

1
2
3
$ git branch -d newB # 该删除操作会先检查分支是否合并到其他分支上,若没有合并则无法删除

$ git branch -D newB # 该操作会直接删除分支,不会检查分支状态

查看分支列表:

1
$ git branch 

查看版本库的发展记录

1
2
3
$ git show-branch

$ git whatchangeddiff-tree {{分支号}}

查看两个版本的差异情况:

1
$ git diff B1 B2

合并其他分支到主分支上:

1
2
3
4
$ git check master
$ git merge -m "merge from NewB" newB

$ git pull . newB

如果在合并分支的过程中,有些相同的行内容不一样,会出现报错,此时就需要参照报错信息手动去解决这些问题。

逆转和恢复

项目跟踪工具的一个重要任务之一,就是使我们能够随时逆转(Undo)和恢复(Redo)某一阶段的工作。

命令形式:

1
git reset [--mixed | --soft | --hard] [<commit-ish>]

其中:

--mixed 仅是重置索引的位置,而不改变你的工作树中的任何东西(即,文件中的所有变化都会被保留,也不标记他们为待提交状态),并且提示什么内容还没有被更新了。这个是默认的选项。
--soft 既不触动索引的位置,也不改变工作树中的任何内容,我们只是要求这些内容成为一份好的内容(之后才成为真正的提交内容)。这个选项使你可以将已经提交的东西重新逆转至“已更新但未提交(Updated but not Check in)”的状态。就像已经执行过 git update-index 命令,但是还没有执行 git commit 命令一样。
--hard 将工作树中的内容和头索引都切换至指定的版本位置中,也就是说自 之后的所有的跟踪内容和工作树中的内容都会全部丢失。因此,这个选项要慎用,除非你已经非常确定你的确不想再看到那些东西了。

提取之前的某个文件的提交覆盖当前工作空间:

1
$ git checkout -f {{fileName}}

署名标签

在 git 中,有两种类型的标签,“轻标签”和“署名标签”。

技术上说,一个“轻标签”和一个分支没有任何区别,只不过我们将它放在了 .git/refs/tags/ 目录,而不是 heads 目录。

1
$ git tag my-first-tag # 新建标签

“署名标签”是一个真正的 git 对象,它不但包含指向你想标记的状态的指针,还有一个标记名和信息,可选的 PGP 签名。你可以通过 -a 或者是 -s 选项来创建“署名标签”。

1
$ git tag -s <tag-name>

远程仓库的建立与合并

在服务器上建立一个git远程仓库,以使其他人可以一起对该项目做 contribution:

1
2
3
$ cd /var/repo/mygit/ # 进入你的仓库目录
$ git --bare init mygit.git # 初始化git版本库
# chmod 777 * #修改目录权限

这样远程版本库就建立好了。

通常的情况下,合并其他的人的工作的情况会比合并自己的分支的情况要多,这在 git 中是非常容易的事情,和你运行 git-merge 命令没有什么区别。事实上,远程合并的无非就是“抓取(fetch)一个远程的版本库中的工作到一个临时的标签中”,然后再使用 git-merge 命令。

1
2
$ git fetch <remote-repository>
$ git rebase {{branchName}} # 将当前工作分支的提交迁移到指定分支上基础上

远程仓库与本地的交互

首先,我们需要建立一个远程仓库在本地的镜像:

1
2
3
4
$ git clone <remote-repository>
或者
$ git remote add origin <remote-repository>
$ git clone origin # 其中的origin为远程仓库的短名称

如果我们对这个镜像做了更改,把这些更改提交:

1
2
$ git add [dirs]
$ git commit -m "message"

如果远程仓库中也发生了更改,需要将远程仓库的更改同步到本地仓库:

1
$ git pull origin master

仓库之间同步时不直接合并,需要先新建一个分支,检查一下不同之处:

1
2
3
4
5
$ git fetch origin master:tempB # 将远程分支导入到名为tempB的临时分支中
$ git whatchanged -p master..tempB # 检查这两个分支的不同之处
可选:
$ git-checkout master # 如果可以接受更改,切换回主分支
$ git pull . tempB # 将tempB分支合并到主分支

当我们需要将本地提交好的分支推送到远程仓库时:

1
$ git push origin master # 将本地提交推送到originmaster分支

一些注意事项

  1. 在第一次初始化仓库时需要指定仓库的的使用者,如名称和邮件地址等,命令如下:
1
2
3
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"

  1. 每次在进行版本或者分支操作时最好先进行一次提交commit,以防止当前所做的更改丢失。
  2. linux与windows的换行符格式不同,在提交时为了防止被CRLF刷屏,可以执行以下命令:
1
2
3
4
5
6
7
8
# 提交时转换为LF,检出时转换为CRLF
git config --global core.autocrlf true

# 提交时转换为LF,检出时不转换
git config --global core.autocrlf input

# 提交检出均不转换
git config --global core.autocrlf false

core.autocrlffalse 时需要配置:

1
2
3
4
5
6
7
8
# 拒绝提交包含混合换行符的文件
git config --global core.safecrlf true

# 允许提交包含混合换行符的文件
git config --global core.safecrlf false

# 提交包含混合换行符的文件时给出警告
git config --global core.safecrlf warn

参考资料

  1. 百度百科-git
  2. 在Linux服务器上搭建Git远程仓库并Push本地库
  3. Git 多平台换行符问题(LF or CRLF)

Git简明实用教程
https://www.eatrice.cn/post/Git简明实用教程/
作者
吃白饭-EatRice
发布于
2020年6月13日
许可协议