尽管自己一直与Github有所接触,比如用Github交个作业啦,Fork一个项目啦……但是对于git
命令的使用还知之甚少。于是我决定对自——
Git,个人博客的开篇决定就是你了!
What’s Git
Git is a distributed version control system developed by Junio Hamano and Linus Torvalds.
Quoting Linus: “I’m an egotistical bastard, and I name all my projects after myself. First ‘Linux’, now ‘Git’”.
(‘git’ is British slang for “pig headed, think they are always correct, argumentative”).
——扒自git.wiki.kernel.org
简而言之,Git就是Linux之父Linus开发的一个分布式版本控制工具。至于Git名称的来源嘛,呵呵,它来自于英国俚语,意思是“蠢货”、“饭桶”,不太友好。
版本控制
所谓“版本控制”的概念,来源于软件工程。一个Project在开发过程中无可避免进行多次迭代,对于每一代,软件工程师会赋予其相应的版本号,还会附上相应的文档,以记录当前迭代所进行的更改。而对于大型工程,在多人协作的情况下版本控制的问题就更加critical。若是管理者手动进行版本控制,则显得异常恐怖。在这种情况下,版本控制软件就应运而生了。
差分编码
版本控制的常用算法是差分编码:对于一个基准版本 Baseline,后续版本在存储时只需要保存与基准版本之间的差异就可以了。差异储存在称为 delta 或 diff 的不连续档案中。由于改变通常很小(平均占全部大小的2%),差分编码能大幅减少资料的重复。一连串独特的 delta 档案在空间上要比未编码的相等档案有效率多。
分布式版本控制
传统的版本控制软件采用的是集中模式的版本控制:不同版本的文件都必须存放在一个中央服务器中,这样就要求一个服务器来集中托管版本库。对于Git这种分布式版本控制系统来说,每一个用户的电脑上都是一个完整的版本库。因而,由服务器故障引发的安全性问题在Git上不可能出现。
多插一句,Git自从诞生之日起,就肩负起了史上最复杂的开源项目Linux Kernel的版本控制工作。它的优越性由此可见一斑。更何况如今Github风靡一时,不妨也来使用Git驱动的Github托管你的代码吧!
Installation
在系统自带的terminal中敲下git
并回车,如果系统显示如下:
1 | ➜ ~ git |
则表明你的系统上已经装有Git,可以跳过安装步骤了。
否则需要根据系统的不同,选择对应方法安装Git:
Win
在Git - Downloading Package下载并安装Git For Windows,然后在系统PATH变量中加入Git的安装目录即可。
macOS
安装Xcode Command Line Tools,这是Apple官方的软件开发工具,包含git, llvm, make
等等常用命令行软件开发程序。
或者,安装Homebrew,这是一款macOS平台上流行的软件包管理工具,“使用Homebrew可以安装 Apple没有预装但你需要的东西”。
Linux
使用Linux下传统的安装工具,如apt,yum等,即可安装Git。
git init - demo
值得注意的是,在开始工作前,首先使用mkdir
命令创建一个工作目录,并且进入这个目录:
1 | mkdir Helloworld |
然后键入git status
命令,会看到如下提示:
1 | ➜ Helloworld git status |
表明现在Helloworld目录还并不是一个git repository,我们需要使用git init
命令来初始化这个目录:
1 | ➜ Helloworld git init |
我们发现shell的prompt也发生了变化,说明初始化成功,接下来我们就可以正式使用Git啦!
Basics
Git 有三种状态,你的文件可能处于其中之一:已提交 committed、已修改 modified 和已暂存 staged 。 已提交表示数据已经安全的保存在本地数据库中。 已修改表示修改了文件,但还没保存到数据库中。 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。而未跟踪 untracted 的文件并未被纳入到Git版本系统之中。
基本的 Git 工作流程如下:
- 在工作目录中修改文件。
- 暂存文件,通过
git add
将文件的快照放入暂存区域,即暂存更新。 - 提交更新,通过
git commit
找到暂存区域的文件,将快照永久性存储到 Git 仓库目录,即提交更新。
对于git init
初始化的目录,所有的文件都默认保持在 Untracked 状态。另外,可通过git status
来查看当前工作目录下的文件状态。
注意:git commit
命令会默认打开vim
,此时在非注释行键入提交信息,保存退出即可提交更新。
git rm
git rm --cached
可以使文件恢复 Untracked 状态,git rm
会直接从目录中删除文件。
而在Git中rm
不能真正删除文件(Git会视为未提交的修改)。
git mv
使用git mv file_from file_to
,可以对文件进行改名,当然传统的mv
命令也可以使用。
git diff
通过git diff
可以查看修改之后还没有暂存起来的变化内容,git diff --cached
可以查看查看已暂存的将要添加到下次提交里的内容。
撤销操作
git commit --amend
:重新进行提交,覆盖上次的提交结果。
git reset HEAD <file>
:取消暂存的文件,其中HEAD^
/HEAD^^
表示上一个和上上个状态,更早版本可以使用HEAD~n
来表示。如果参数是HEAD
则表示暂存区的修改回退到工作区中。
git checkout --<file>
:撤销对文件的修改(即恢复到最近一次commit或者add的状态)慎用!
小结
来自廖雪峰的Git教程:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout --file
。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,使用get reset HEAD^
、`get reset –hard commit_id等命令,不过前提是没有推送到远程库。
git branch
使用git branch branch_name
来创建分支,git checkout branch_name
来改变当前分支(注意git checkout
还有撤销修改的功能!)git merge branch_name
将某个分支合并到当前分支上。
此外,git checkout -b branch_name
则将branch
和checkout
两条命令合一;git checkout -d branch_name
代表删除分支。
Git 的分支实质上仅是包含所指对象校验和(长度为 40 的 SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。 创建一个新分支就相当于往一个文件中写入 41 个字节(40 个字符和 1 个换行符)。branch种种高效的特性使得Git鼓励开发人员频繁地创建和使用分支!
远程仓库
使用git clone [url]
克隆现有的仓库,而git remote add <shortname> <url>
可将本地仓库与已有远程仓库关联起来,按照惯例远程仓库通常命名为origin,git clone
默认关联的远程仓库代号也是origin。
git push origin branch_name
将本地分支的修改推送到远程仓库origin上,git pull branch_name origin
将本地分支抓取远程origin分支并且自动尝试合并。git fetch [remote_name]
可以拉取远程仓库上的所有分支。
本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致;建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
;
git remote
附加命令还有:
command_name | 描述 |
---|---|
git remote rename |
重命名远程仓库的代号 |
git remote rm |
移除与远程仓库的关联 |
git remote show shortname |
显示某一远程分支的相关信息 |
git remote [-v] |
显示所有关联的远程分支 |
Exotic
git log
默认不用任何参数的话,git log
会按提交时间列出所有的更新,最近的更新排在最上面。 这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
命令行参数 | 含义 | 命令行参数 | 含义 |
---|---|---|---|
-p | 显示每次提交的差异 | -(n) | 显示最近提交的n次修改的内容 |
–stat | 查看每次提交的简要统计信息 | –pretty=oneline/full/format | 定制化显示记录格式 |
–graph | 添加一些ASCII字符串来展示分支、合并历史 | –shortstat | 只显示 –stat 中最后的行数修改添加移除统计 |
–name-only | 仅在提交信息后显示已修改的文件清单 | –name-status | 显示新增、修改、删除的文件清单 |
–abbrev-commit | 仅显示 SHA-1 的前几个字符 | –relative-date | 使用较短的相对时间显示 |
–since/until | 按照时间筛选 | –author | 按照作者筛选 |
–grep | 以正则匹配来筛选 | -S | 仅显示添加或移除了某个关键字的提交 |
git tag
git tag <tagname>
为当前分支打标签,git show <tagname>
显示相应标签的提交信息, git tag -d <tagname>
则可以删除相应标签。标签在Git中非常实用,可以通过标签创见新的分支。
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。 在创建完标签后必须显式地推送标签到共享服务器上:使用命令git push origin <tagname>
。
git stash
假设说开发dev
分支过程中突然需要修复一个bug,可以使用git stash
命令来保存未完成的现场,然后工作区会变为last commit的状态。此时,就可以安心从master分支来修复bug了。完成之后,如何恢复之前stash的未完成状态呢?
首先切换回dev
分支,使用git stash list
查看之前stash的内容,然后有两种选择:
git stash pop
就像弹栈,恢复并删除上次stash的内容git stash apply stash@{n}
可以指定恢复某个stash,git stash drop
可以删除相应stash
.gitignore
通过编辑这个文件,可以让Git“无视”工作目录下的某些文件。
实例如下:
1 | # no .a files |
配置Git
git config --global config_name value
是设置全局配置的通法,git config
则只对当前目录有效。通常需要设置的是user.name
、user.email
、core.editor
等变量。可以通过git config --list
查看所有配置。
git config alias.alias_name 'original_command'
可以为变量设置别名。