关于 Git

Git 背后的故事

  • 伟大的作品总是诞生于伟大的时代,正如 Git 同样诞生于一个英雄辈出、极富纷争的年代。
  • 2005 年,Linux 内核开发社区正面临严峻的挑战:他们不能继续使用 BitKeeper 了(注:原因是当时BitKeeper 著作权所有者决定收回授权,内核开发团队与其协商无果),而又没有其他的 SCM (Software Configuration Management)可满足他们的分布式系统的需求。Linux 之父 Linus Torvalds 接受了这个挑战,决定开发一个新的版本控制系统,并制定了分布式、非线性、简单快速的设计目标。周末他消失了,新的一周,Git 问世了。
  • 自诞生以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。今天,Git 已经成为上万个项目的版本控制系统,并且在程序员中引发了开源热潮。

基本概念
和 SVN 相比,Git 有一些独特的术语和概念,有必要了解一下。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
  • 工作区(working tree):可以理解为客户端电脑上的项目路径
  • 版本库(repository):工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库
  • 暂存区(stage):存放在 .git 目录下下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)
  • 默认的远程版本库(origin):尽管 Git 是分布式的,但它不排斥中心服务器
  • 工作区、版本库中的暂存区和版本库,以及远程库之间的关系如下:

Git 程序员篇 Python 第1张

图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。

git add

  • 暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。

git commit

  • 暂存区的目录树写到版本库(对象库)中,HEAD 指向分支会做相应的更新。

git reset HEAD

  • 暂存区的目录树会被重写,被HEAD 指向分支的目录树所替换,但是工作区不受影响。

git rm --cached

  • 直接从暂存区删除文件,工作区则不做出改变。

git checkout 或者 git checkout –

  • 暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

git checkout HEAD 或者 git checkout HEAD

  • HEAD 指向的分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

git clone git@sdysit.com:/sdyouth/git/yangmaosen.git

  • 从远程库克隆项目

git fetch

  • 从远程的分支获取最新的版本到本地。

get push

  • 将本地版本库的分支推送到远程库上对应的分支。

术语中英文对照

English                       中        文
# ---------------------------------------------------------------------------------------------
3-way merge                 # 三方合并
abbreviate             # 简写(的 SHA-1 值)
alternate object database    # 备用对象库
amend                # 修补
ancestor              # 祖先,祖先提交
annotated tag           # 附注标签
bare repository          # 纯仓库
bisect                # 二分查找
blob object             # 数据对象
branch                  # 分支
bundle                #
bypass                # 绕过
cache                # 索引(的别称)
chain                # (提交)链
changeset              # 变更集
checkout               # 检出
checksum               # 校验,校验和
cherry-picking           # 拣选
# ---------------------------------------------------------------------------------------------
clean                # 干净(的工作区)
clone                # 克隆
commit                # 提交
commit message          # 提交说明
commit object           # 提交对象
commit-ish (also committish) # 提交号
conflict           # 冲突
core Git           # 核心 Git 工具
DAG              # 有向无环图
dangling object       # 摇摆对象
detached HEAD        # 分离头指针
directory           # 目录
dirty             # 脏(的工作区)
dumb HTTP protocol     # 哑 HTTP 协议
evil merge          # 坏合并(合并引入了父提交没有的修改)
fast-forward        # 快进
fetch            # 获取
file system        # 文件系统
fork            # 派生
Git archive        # 仓库(对于 arch 用户)
gitfile          # gitfile(仓库链接文件)
grafts          # (提交)移植
# ---------------------------------------------------------------------------------------------
hash            # 哈希值
HEAD            # HEAD(头指针,亦即当前分支)
head            # 头、分支
head ref          # 分支
header            # 头信息
hook            # 钩子
hunk            # 补丁片段
index            # 索引
index entry         # 索引条目
loose object        # 松散对象
loose refs          # 松散引用
master            # master(默认分支名)
merge            # 合并
object            # 对象
object database      # 对象库
object identifier      # 对象标识符
object name        # 对象名称
object type        # 对象类型
octopus          # 章鱼式合并(两分支以上的合并)
origin           # origin(默认的远程名称)
pack            #
pack index         # 包索引
packfile          # 包文件
parent            # 父提交
patch            # 补丁
# ---------------------------------------------------------------------------------------------
pathspec          # 路径规格
pattern          # 模式
pickaxe          # 挖掘
plumbing          # 管件(Git 底层核心命令的别称)
porcelain          # 瓷件(Git 上层封装命令的别称)
precious-objects repo  # 珍品仓库
prune            # 清除
pull            # 拉,拉取
push            # 推,推送
reachable         # 可达
rebase           # 变基
ref             # 引用
reflog           # 引用日志
refspec          # 引用规格
remote           # 远程,远程仓库
remote-tracking branch  # 远程跟踪分支
replay          # 重放
repo           # 仓库
repository       # 仓库
resolve        # (冲突)解决
revert        # 还原
revision       # 版本
rewind         # 回退
# ---------------------------------------------------------------------------------------------
SCM           # 源代码管理(工具)
SHA-1           # SHA-1(安全哈希算法1)
shallow repository    # 浅(克隆)仓库
signed tag         # 签名标签
smart HTTP protocol # 智能 HTTP 协议
squash          # 压缩
stage          # n. 暂存区(即索引); v. 暂存
stash         # n. 贮藏区; v. 贮藏
submodule      # 子模组
symref        # 符号引用
tag          # n. 标签; v. 打标签
tag object      # 标签对象
tagger         # 打标签者
topic branch      # 主题分支
track          # 跟踪
trailer         # 尾部署名
tree           # 树(工作区或树对象)
tree object       # 树对象
tree-ish (also treeish)  # 树对象(或可以解析为一树对象)
unmerged index      # 未合并索引
unpack           # 解包
unreachable object    # 不可达对象
unstage           # 取消暂存
upstream           # 上游
upstream branch       # 上游分支
working tree          # 工作区

 

安装Git客户端

Git 目前几乎可以运行在包括 Linux/Unix、Solaris、Mac和 Windows 等所有平台上。Git 各平台安装包下载地址为:http://git-scm.com/downloads

Linux 平台安装
Git 的工作需要调用 curl,zlib,openssl,expat,libiconv 等库的代码,所以需要先安装这些依赖工具。如果你碰巧用 Debian 或 Ubuntu,使用下面的命令,就可以直接完成Git的安装。

sudo apt-get install git

 

Windows 平台

写这篇博客的时候,最新的 Git 客户端版本是 Git-2.19.1。点此下载最新的安装文件,然后运行,按默认选项安装即可。我大概只更改了默认的编辑器,其他接受了默认选项。

友情提示:关于行结束符,默认的选择是 checkout 时从 LF 转 CRLF,commit 时 从 CRLF 转 LF。这样设置适合跨平台的开发,不过 add 操作时会出现警告,忽略即可。

 Git 程序员篇 Python 第2张

 

 Git 程序员篇 Python 第3张

 

 Git 程序员篇 Python 第4张

 

 Git 程序员篇 Python 第5张

 

 Git 程序员篇 Python 第6张

 

 Git 程序员篇 Python 第7张

 

 Git 程序员篇 Python 第8张

安装完成后,右键菜单会增加 Git GUI 和 Git Bash 两项。用户可以根据自己的习惯选择使用 Git GUI 或 Git Bash 来创建、管理自己的版本库。

 Git 程序员篇 Python 第9张

在非本地版本库的工作区打开 Git GUI,界面如下:

Git 程序员篇 Python 第10张

这里,可以创建本地版本库,可以克隆远程库,也可以打开本地已经存在的版本库。

在本地版本库的工作区打开 Git GUI,界面如下:

Git 程序员篇 Python 第11张

  • 版本库中新增加的或者修改过的文件将会出现在左侧上方的窗口中。也可以点击“Rescan”按钮重新检查新增加的或者修改过的文件,以更新左侧上方的窗口显示内容。
  • 点击“Stage Changed”按钮,新增加的或者修改过的文件将会从左侧上方的窗口移到左侧下方的窗口中,完成文件暂存。点击暂存区的单个文件图标,该文件将回退到未暂存的状态。
  • 点击“Commit”按钮,已经暂存的文件将被提交到版本库——特别说明,这里的版本库是指本地库,而非远程库。点击“Push”按钮,才可以将本地库的当前分支提交到远程库。关于分支,将在后面详细说明。

 

使用 Git

  • 理解了 Git 的理念,使用 Git 是一个很自然的过程,不管是在 windows 平台还是 linux 平台上,不管用 Git GUI 还是 Git Bash。本博文主要介绍 windows 平台上的使用,以 Git GUI 为主,间或使用 Git Bash。

客户端生成数字证书

  • Git 是分布式的,可以不依赖于远程库而独立工作。因此,数字证书不是必须的。如果打算连接远程库,这项准备工作只需要做一次。

假定有一个远程库:

  • ssh://git@sdysit.com:22/sdyouth/git/GitTest.git

因为使用了的是默认端口,可以简写为:

  • git@sdysit.com:/sdyouth/git/GitTest.git
  • 出于安全考虑,只有数字证书公钥保存在 Git 服务器的 Git 客户端才能连接这个远程库。通常,Git 客户端的数字证书保存在 C:\Users\用户名.ssh 路径下。
  • 如果 Git 客户端不存在 C:\Users\用户名.ssh 路径,请启动 Git Bash,尝试从远程库克隆 test 项目:
$ git clone git@sdysit.com:/sdyouth/git/GitTest.git

第一次连接到目标 Git 服务器时会得到一个提示:

Cloning into 'GitTest'...
The authenticity of host 'sdysit.com (120.55.169.217)' can't be established.
ECDSA key fingerprint is SHA256:tTXVyJPoqCiEZP3+3E2uOOmvXIWGEWtCcUOgBhlb+iQ.
Are you sure you want to continue connecting (yes/no)? yes

选择 yes

Warning: Permanently added 'sdysit.com,120.55.169.217' (ECDSA) to the list of known hosts.
git@sdysit.com's password:
Connection closed by 120.55.169.217 port 22
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
  • 最终的结果肯定是失败的,即使你输入了正确的密码。但我们已经将此服务器加入到了已知服务器列表中。此时 C:\Users\用户名.ssh 下会多出一个文件 known_hosts,以后在这台电脑上再次连接目标 Git 服务器时不会再提示上面的语句。

如果 Git 客户端存在 C:\Users\用户名.ssh 路径,则直接在 Git Bash 执行以下命令,生成数字证书:

$ ssh-keygen -t rsa -C "yangmaosen@sdysit.com"
  • yangmaosen@sdysit.com 是我的用户名。每个用户都应该有自己的有别于其他用户的用户名。虽然 Git 不限定用户的操作权限,但是管理员需要知道来访者是谁,以便于在该用户离开团队时,从服务端删除他的数字证书公钥。
  • 现在,C:\Users\用户名.ssh 下会多出两个文件 id_rsa 和 id_rsa.pub,id_rsa 是私钥,id_rsa.pub 是公钥。请把公钥文件交给管理员(出于安全考虑,这里不讨论管理员的工作),很快你就成为远程库的合法用户了。管理员也许会给你一个密码,请牢记并妥善保管。

 

从远程库克隆项目

前文已经展示过使用 Git Bash 克隆版本库,下图为使用 Git GUI 从远程库克隆 FY-3 项目到本地 D:\YouthGit 路径下。友情提示:如果 D:\YouthGit 路径下已经存在 FY-3 文件夹,将无法完成克隆。

 Git 程序员篇 Python 第12张

 

创建本地版本库

以在本地 D:\YouthGit 路径下创建 FY-2 项目为例。启动 Git Bash,执行以下操作即可。

yms@LAPTOP-07EQCT4C MINGW64 /d/YouthGit
$ pwd
/d/YouthGit

yms@LAPTOP-07EQCT4C MINGW64 /d/YouthGit
$ mkdir FY-2

yms@LAPTOP-07EQCT4C MINGW64 /d/YouthGit
$ cd FY-2

yms@LAPTOP-07EQCT4C MINGW64 /d/YouthGit/FY-2
$ git init
Initialized empty Git repository in D:/YouthGit/FY-2/.git/

yms@LAPTOP-07EQCT4C MINGW64 /d/YouthGit/FY-2 (master)

如果使用 Git GUI,创建本地项目版本库如下图所示。

 Git 程序员篇 Python 第13张

关联本地版本库到远程库
在本地创建的版本库,要关联到远程库,前提是被关联的远程库必须存在。以在本地 D:\YouthGit 路径下创建 的FY-2 项目为例,使用 Git GUI 关联到远程库 git@sdysit.com:/sdyouth/git/FY-2.git,需要添加远程库。点击菜单Remote --> Add…,在弹出窗口中正确填入远程库路径,并给远程库取一个恰当的名字,点击 Add 按钮即可完成操作。

 Git 程序员篇 Python 第14张

检查工作区

  • 当工作区新增加了文件,或者原有的文件有改变时,启动 Git GUI 后会自动显示在未暂存文件列表中。点击“Rescan”按钮,也可以重新检查新增加的或者修改过的文件,以更新左侧上方的窗口显示内容。

保存更新暂存区

  • 点击“Stage Changed”按钮,新增加的或者修改过的文件将会从左侧上方的窗口移到左侧下方的窗口中,完成文件暂存。点击暂存区的单个文件图标,该文件将回退到未暂存的状态。

提交更新至版本库

  • 点击“Commit”按钮,已经暂存的文件将被提交到版本库——特别说明,这里的版本库是指本地库,而非远程库。每次 commit 之前,请务必填写说明,否则 Git GUI 将会拒绝执行命令。关于本次 commit 的说明,对于合作者,以及以后的开发工作有着非常重要的作用。

Git 程序员篇 Python 第15张

创建分支
假定在 FY-2 项目中创建以 master 分支当前代码为起点的 demo 分支,点击 Git GUI 菜单 Branch --> Create…,在弹出窗口中照下图操作即可。创建新的分支后,Git GUI 自动切换到新的分支,并更新工作区。

 Git 程序员篇 Python 第16张

切换分支
点击 Git GUI 菜单 Branch --> Checkout…,在弹出窗口中照下图操作,即可切换到 master 分支,同时更新工作区。

 Git 程序员篇 Python 第17张

合并分支
点击 Git GUI 菜单 Merge --> Local Merge…,在弹出窗口中照下图操作,即将 domo 分支合并到 master 分支上。

 Git 程序员篇 Python 第18张

将本地的分支推送到远程库
点击 Push 按钮,在弹出窗口上照下图操作,即可将本地库的 master 分支推送到远程库。

 Git 程序员篇 Python 第19张

获取远程库的最新版本
点击 Git GUI 菜单 Remote --> Fetch from,在第三级菜单中选择恰当的远程库,在弹出窗口中照下图操作,即可获取远程库的最新版本。

Git 程序员篇 Python 第20张

另外,我们还可以选择 Remote --> Rrune from 来完成更新。git fetch 和 git pull 的区别在于:

  • git fetch:相当于是从远程获取最新版本到本地,不会自动merge
  • git pull:相当于是从远程获取最新版本并merge到本地

在实际使用中,git fetch更安全一些,因为在merge前,我们可以查看更新情况,然后再决定是否合并。比如,使用 Git Bash 执行 git fetch,可以完成更精确的操作。

git fetch origin master:tmp
git diff tmp 
git merge tmp

 

Git 常用命令集

符号说明:

  • 尖括号(< >)表示需要替换成尖括号内文字描述的内容
  • 方括号([ ])表示可选项
  • 远程库名,形如 git@sdysit.com:/sdyouth/git/GitTest.git
  • 路径名,形如 D:\YouthGit\GitTest 或者 GitTest

初始化操作:

$ git config --list   # 检查已有的配置信息
$ git config --global user.name <name>   # 设置提交者名字
$ git config --global user.email <email>   # 设置提交者邮箱
$ git config --global core.editor <editor>   # 设置默认文本编辑器
$ git config --global merge.tool <tool>      # 设置解决合并冲突时差异分析工具

创建新的版本库:

$ git init [--bare] [path] # 在当前路径或 path 下创建版本库。客户端不建议使用 bare 参数

克隆已经存在的版本库:

$ git clone <remote> [path] # 在当前路径或 path 下克隆远程库

修改和提交:

$ git add .   # 添加所有改动过的文件
$ git add <file>   # 添加指定的文件
$ git mv <old> <new>   # 文件重命名
$ git rm <file>   # 删除文件
$ git rm -cached <file>   # 停止跟踪文件但不删除
$ git commit -m <file>   # 提交指定文件
$ git commit -m “commit message”   # 提交所有更新过的文件
$ git commit -amend   # 修改最后一次提交
$ git commit -C HEAD -a -amend   # 增补提交(不会产生新的提交历史纪录)

查看提交历史:

$ git log   # 查看提交历史
$ git log -p <file>   # 查看指定文件的提交历史
$ git blame <file>   # 以列表方式查看指定文件的提交历史
$ gitk   # 查看当前分支历史纪录
$ gitk <branch>   # 查看某分支历史纪录
$ gitk --all   # 查看所有分支历史纪录
$ git branch -v   # 每个分支最后的提交
$ git status   # 查看当前状态
$ git diff   # 查看变更内容

撤消操作:

$ git reset -hard HEAD   # 撤消工作目录中所有未提交文件的修改内容
$ git checkout HEAD <file1> <file2>  # 撤消指定的未提交文件的修改内容
$ git checkout HEAD.  # 撤消所有文件
$ git revert <commit> # 撤消指定的提交

分支与标签:

$ git branch     # 显示所有本地分支
$ git checkout <branch/tagname>   # 切换到指定分支或标签
$ git branch <new-branch>   # 创建新分支
$ git branch -d <branch>   # 删除本地分支
$ git tag   # 列出所有本地标签
$ git tag <tagname>   # 基于最新提交创建标签
$ git tag -d <tagname>   # 删除标签

合并与衍合:

$ git merge <branch>  # 合并指定分支到当前分支
$ git rebase <branch>   # 衍合指定分支到当前分支

远程操作:

$ git remote -v         # 查看远程版本库信息
$ git remote show <remote>     # 查看指定远程版本库信息
$ git remote add <remote> <url>  # 添加远程版本库
$ git fetch <remote>         # 从远程库获取代码
$ git pull <remote> <branch>     # 下载代码及快速合并
$ git push <remote> <branch>      # 上传代码及快速合并
$ git push <remote> : <branch>/<tagname> # 删除远程分支或标签
$ git push -tags                 # 上传所有标签

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄