Git教程
1. Git简介
在学习git时,偶然看到Git的诞生,觉得很有趣,被Linuxs的桀骜不驯和任性所感染,故写下这一段提醒自己,作为一个程序员要有追求。
- Git的诞生
在1991年Linus创建了开源的Linux,从此,Linux系统经过不断的发展,成为了世界上最大的服务器软件。Linus虽然创建了Linux,但是Linux的壮大是靠全世界热心的志愿者共同努力的结果。那么linux的代码是如何管理的呢?事实上,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工的方式合并代码。
你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但都是付费的,和Linux的开源精神不符。
到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工的方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的局面在2005年被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错),于是BitKeeper公司怒了,要收回Linux社区的免费使用权。
Linus可以向BitKeeper公司道个歉,保证以后严格管教弟兄们,但,这是不可能的。实际情况是:Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源代码已经由Git管理了!Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了。它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub。
2. Git的安装配置
最早的Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上运行。后来有人将它移植到了Windows上。目前,Git支持Linux/Unix、Solaris、Mac和 Windows 平台上运行。
Git 各平台安装包下载地址为:http://git-scm.com/downloads
2.1 Linux平台上安装Git
Git 的工作需要调用 curl,zlib,openssl,expat,libiconv 等库的代码,所以需要先安装这些依赖工具。
在有 yum 的系统上(比如 Fedora)或者有 apt-get 的系统上(比如 Debian 体系),可以用下面的命令安装:
各 Linux 系统可以使用其安装包管理工具(apt-get、yum 等)进行安装:
- Debian/Ubuntu Git 安装命令为:
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
libz-dev libssl-dev
$ apt-get install git
$ git --version
git version 1.8.1.2
- Centos/RedHat 安装命令为:
$ yum install curl-devel expat-devel gettext-devel \
openssl-devel zlib-devel
$ yum -y install git-core
$ git --version
git version 1.8.3.1
- 源码安装
安装指定系统的依赖包:
########## Centos/RedHat ##########
$ yum install curl-devel expat-devel gettext-devel \
openssl-devel zlib-devel
########## Debian/Ubuntu ##########
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
libz-dev libssl-dev
解压安装下载的源码包:
$ tar -zxf git-1.7.2.2.tar.gz
$ cd git-1.7.2.2
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install
2.2 Windows平台上安装
在Windows上使用Git,可以从Git官网直接下载安装程序,(网速慢的同学请移步国内镜像),然后按默认选项安装即可。
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
2.3 Git配置
Git提供了一个叫做git config的工具,专门用来配置或读取相应的工作环境变量。这些环境变量,决定了Git在各个环节的具体工作方式和行为。这些变量存放在以下三个不同的地方:
- /etc/gitconfig文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
- ~/.gitconfig文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
- 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。
- 配置个人的用户名和电子邮件地址:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。
如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
- 查看配置信息
$ git config --list
user.name="Your Name"
user.email="email@example.com"
有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 ~/.gitconfig),不过最终 Git 实际采用的是最后一个。
- 文本编辑器
设置Git默认使用的文本编辑器, 一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置:
$ git config --global core.editor emacs
- 差异分析工具
$ git config --global merge.tool vimdiff
3. 创建版本库
Git使用git init命令来初始化一个Git仓库,在执行完git init命令后,Git仓库会生成一个.git目录,该目录包含了资源的所有元数据,其他的项目目录保持不变(SVN会在每个子目录生成.svn目录,Git只会在仓库的根目录生成.git目录)。
如果使用当前目录作为Git仓库,只需要执行如下命令:
$ git init
如果需要指定目录作为Git仓库,需要执行下面的命令:
$ git init DirName
如果目录DirName不存在,会自动创建DirName目录,并在DirName生成.git目录。
用命令git add将文件添加到仓库:
$ git add *.c
$ git add README
用命令git commit将文件提交到仓库:
// -m 后面输入的是本次提交的说明
$ git commit -m "上传源文件"
// -a 可以跳过git add这一步
git commit -am "修改README文件"
可以使用git clone从现有的Git仓库中拷贝项目(类似svn checkout)
// repo:Git仓库
// directory:本地目录
$ git clone <repo> <directory>
git clone 时,可以所用不同的协议,包括 ssh, git, https 等,其中最常用的是 ssh,因为速度较快,还可以配置公钥免输入密码。各种写法如下:
git clone git@github.com:fsliurujie/test.git --SSH协议
git clone git://github.com/fsliurujie/test.git --GIT协议
git clone https://github.com/fsliurujie/test.git --HTTPS协议
4. Git基本命令说明
4.1 git status
git status可以查看在你上次提交之后是否有修改,添加参数 -s,以获取简短的结果输出
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README
4.2 git diff
执行git diff来查看git status结果的详细信息
git diff命令可以显示已写入缓存与已修改但尚未写入缓存的改动的区别。git diff主要的应用场景如下:
- 尚未缓存的改动:git diff
- 查看已缓存的改动:git diff --cached
- 查看已缓存的与未缓存的所有改动:git diff README
- 显示摘要而非整个diff:git diff --stat
$ git diff
diff --git a/README b/README
index e69de29..d5a31d0 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+123534
\ No newline at end of file
$ git diff --cached
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
$ git diff README
diff --git a/README b/README
index e69de29..d5a31d0 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+123534
\ No newline at end of file
$ git diff --stat
README | 1 +
1 file changed, 1 insertion(+)
4.3 git reset
git reset命令用于取消已缓存的内容:
$ git add .
$ git status -s
A README
A hello.c
$ git reset README
$ git status -s
A hello.c
?? README
$ git commit -m "上传hello.c文件"
[master (root-commit) 3608101] 123
1 file changed, 5 insertions(+)
create mode 100644 hello.c
执行git commit命令后,只会讲hello.c文件的改动提交,而README不会提交。
4.4 git rm
要从Git中移除某个文件,需要执行git rm
git rm <file>
如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f
git rm -f <file>
如果把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 --cached 选项即可
git rm --cached <file>
可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件:
git rm –r *
5. Git分支管理
列出分支命令:
$ git branch
* master
本地有一个master的分支,当执行git init命令后,默认情况下Git就会创建master分支。
手动创建一个分支:
$ git branch testing
$ git branch
* master
testing
当你以此方式在上次提交更新之后创建了新分支,如果后来又有更新提交, 然后又切换到了 testing 分支,Git 将还原你的工作目录到你创建分支时候的样子。
可以使用git checkout切换到我们需要修改的分支:
$ git checkout testing
Switched to branch 'testing'
$ git branch
master
* testing
可以使用git checkout -b命令来创建新分支并立即切换到该分支下:
$ git checkout -b newtest
Switched to a new branch 'newtest'
$ git branch
master
* newtest
testing
5.1 删除分支
删除分支的命令:
$ git branch -d testing
Deleted branch testing (was 3608101).
$ git branch
master
* newtest
5.2 分支合并
$ git branch
* master
newtest
$ ls
README test.txt
$ git merge newtest
Updating 3e92c19..c1501a2
Fast-forward
runoob.php | 0
test.txt | 1 -
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt
$ ls
README runoob.php
5.3. 合并冲突
在newtest分支修改文件README并提交
$ git commit -am "changed the README"
warning: LF will be replaced by CRLF in README.
The file will have its original line endings in your working directory
[newtest 06c9e5c] changed the README
1 file changed, 1 insertion(+)
切换到master分支,并修改README文件并提交:
$ git commit -am "修改README"
[master 658ec34] 修改README
1 file changed, 2 insertions(+)
create mode 100644 README
将newtest分支合并到master分支:
$ git merge newtest
CONFLICT (add/add): Merge conflict in README
Auto-merging README
Automatic merge failed; fix conflicts and then commit the result.
查看冲突
$ cat README
<<<<<<< HEAD
12345
master branch change
=======
123534
newtest branch change
>>>>>>> newtest
编辑完冲突后,可以使用git add来告诉Git文件冲突已解决
$ git status -s
AA README
$ git add README
$ git commit
[master f5ee2a4] Merge branch 'newtest'
6. Git查看提交历史
使用git log命令可以列出历史提交记录:
$ git log
commit f5ee2a44cc75a60f73008ed1ae936de5071caeb0 (HEAD -> master)
Merge: 658ec34 06c9e5c
Author: caixuefeng <mail>
Date: Thu Jan 16 16:13:38 2020 +0800
Merge branch 'newtest'
commit 658ec346d53e23452715e6c77eb3a012b173a614
Author: caixuefeng <mail>
Date: Thu Jan 16 16:06:59 2020 +0800
修改README
commit 06c9e5c953fc0acf8ea052815a38ba6f590b1017 (newtest)
Author: caixuefeng <mail>
Date: Thu Jan 16 16:01:57 2020 +0800
changed the README
commit a6b1c683992231aa25a48826b25ffda3457c77f0
Author: caixuefeng <mail>
Date: Thu Jan 16 16:01:05 2020 +0800
可以用 --oneline选项来查看历史记录的简洁版本
$ git log --oneline
f5ee2a4 (HEAD -> master) Merge branch 'newtest'
658ec34 修改README
06c9e5c (newtest) changed the README
a6b1c68 changed the README
3608101 123
查找指定用户的提交日志可以使用命令:git log --author
$ git log --author=caixuefeng --oneline
f5ee2a4 (HEAD -> master) Merge branch 'newtest'
658ec34 修改README
06c9e5c (newtest) changed the README
a6b1c68 changed the README
3608101 123
如果你要指定日期,可以执行几个选项:–since 和 --before,但是你也可以用 --until 和 --after。
$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
5469e2d Git 1.7.1-rc2
d43427d Documentation/remote-helpers: Fix typos and improve language
272a36b Fixup: Second argument may be any arbitrary string
b6c8d2d Documentation/remote-helpers: Add invocation section
5ce4f4e Documentation/urls: Rewrite to accomodate transport::address
00b84e9 Documentation/remote-helpers: Rewrite description
03aa87e Documentation: Describe other situations where -z affects git diff
77bc694 rebase-interactive: silence warning when no commits rewritten
636db2c t3301: add tests to use --format="%N"
7. Git标签
当项目达到一个重要的阶段,并希望永远记住那个特别的提交快照,可以使用git tag给他打上标签。当你执行 git tag -a 命令时,Git 会打开你的编辑器,让你写一句标签注解,就像你给提交写注解一样。
$ git tag -a v1.0
如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。
例如,假设我们发布了提交 85fc7e7(上面实例最后一行),但是那时候忘了给它打标签。 我们现在也可以:
$ git tag -a v0.9 3608101
$ git log --oneline --decorate --graph
* f5ee2a4 (HEAD -> master, tag: v1.0) Merge branch 'newtest'
|\
| * 06c9e5c (newtest) changed the README
| * a6b1c68 changed the README
* | 658ec34 修改README
|/
* 3608101 (tag: v1.1) 123
可以用git tag命令查看所有标签:
$ git tag
v1.0
v1.1
指定标签信息命令:
git tag -a <tagname> -m "runoob.com标签"
8. Git远程仓库
可以通过如下命令来添加一个远程仓库:
git remote add [shortname] [url]
由于本地Git仓库和GitHub仓库之间得的传输是通过SSH加密的,所以需要配置验证信息,使用以下命令生成SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
// youremail@example.com为你在GitHub上注册的邮箱
之后会要求确认路径和输入密码,可以使用默认的,直接一路回车就行。成功后会生成.ssh文件夹,打开id_rsa.pub,复制里面的key。
在github上,进入Account==>Settings
左边选择SSH and GPG keys,然后点击New SSH key按钮,设置title(可以随便填),在key上粘贴电脑上生成的key。
添加成功后的界面如下:
可以通过如下命令来验证是否成功:
$ ssh -T git@github.com
The authenticity of host 'github.com (13.229.188.59)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com,13.229.188.59' (RSA) to the list of known hosts.
Hi caixuefeng9! You've successfully authenticated, but GitHub does not provide shell access.
登陆GitHub后,点击New repository来创建GitHub仓库,如下图所示:
之后在在Repository name 填入 runoob-git-test(远程仓库名) ,其他保持默认设置,点击"Create repository"按钮,就成功地创建了一个新的Git仓库:
创建成功后,显示如下信息:
信息告诉我们可以从这个仓库克隆出新的仓库,也可以把本地仓库的内容推送到GitHub仓库。
现在,我们根据 GitHub 的提示,在本地的仓库下运行命令:
$ mkdir runoob-git-test # 创建测试目录
$ cd runoob-git-test/ # 进入测试目录
$ echo "# runoob-git-test" >> README.md # 创建 README.md 文件并写入内容
$ ls # 查看目录下的文件
README
$ git init # 初始化
$ git add README.md # 添加文件
$ git commit -m "添加 README.md 文件" # 提交并备注信息
[master (root-commit) 0205aab] 添加 README.md 文件
1 file changed, 1 insertion(+)
create mode 100644 README.md
# 提交到 Github
$ git remote add origin git@github.com:caixuefeng91/runoob-git-test.git
$ git push -u origin master
8.1 查看当前的远程库
要查看当前配置有哪些远程仓库,可以用以下命令,执行时加上 -v 参数,你还可以看到每个别名的实际链接地址。
$ git remote
origin
$ git remote -v
origin git@github.com:caixuefeng9/runoob-git-test.git (fetch)
origin git@github.com:caixuefeng9/runoob-git-test.git (push)
8.2 提取远程仓库
Git 有两个命令用来提取远程仓库的更新。
1、从远程仓库下载新分支与数据:
git fetch
该命令执行完后需要执行git merge 远程分支到你所在的分支。
2、从远端仓库提取数据并尝试合并到当前分支:
git merge
该命令就是在执行 git fetch 之后紧接着执行 git merge 远程分支到你所在的任意分支。
假设你配置好了一个远程仓库,并且你想要提取更新的数据,你可以首先执行 git fetch [alias] 告诉 Git 去获取新的数据,然后你可以执行 git merge [alias]/[branch] 以将服务器上的任何更新(假设有人这时候推送到服务器了)合并到你的当前分支。
接下来我们在 Github 上点击" README.md" 并在线修改它:
然后在本地更新修改:
$ git fetch origin
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:caixuefeng9/runoob-git-test
acd0703..7d53fdd master -> origin/master
以上信息"acd0703…7d53fdd master -> origin/master" 说明 master 分支已被更新,我们可以使用以下命令将更新同步到本地:
$ git merge origin/master
Updating acd0703..7d53fdd
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)
查看 README.md 文件内容:
$ cat README.md
# runoob-git-test
2020/1/18 第一次修改
8.3 推送到远程仓库
推送你的新分支与数据到某个远端仓库命令:
git push [alias] [branch]
以上命令将你的 [branch] 分支推送成为 [alias] 远程仓库上的 [branch] 分支,实例如下:
$ touch runoob-test.txt # 添加文件
$ git add runoob-test.txt
$ git commit -m "添加到远程"
master 69e702d] 添加到远程
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 runoob-test.txt
$ git push origin master # 推送到 Github
8.4 删除远程仓库
删除远程仓库你可以使用命令:
$ git remote -v
origin git@github.com:caixuefeng9/runoob-git-test.git (fetch)
origin git@github.com:caixuefeng9/runoob-git-test.git (push)
# 添加仓库 origin2
$ git remote add origin2 git@github.com:caixuefeng9/runoob-git-test.git
$ git remote -v
origin git@github.com:caixuefeng9/runoob-git-test.git (fetch)
origin git@github.com:caixuefeng9/runoob-git-test.git (push)
origin2 git@github.com:caixuefeng9/runoob-git-test.git (fetch)
origin2 git@github.com:caixuefeng9/runoob-git-test.git (push)
# 删除仓库 origin2
$ git remote rm origin2
$ git remote -v
origin git@github.com:caixuefeng9/runoob-git-test.git (fetch)
origin git@github.com:caixuefeng9/runoob-git-test.git (push)
9. Git服务器搭建
接下来我们将以 Centos 为例搭建 Git 服务器作为私有仓库使用:
1、安装Git
$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel
$ yum install git
接下来我们 创建一个git用户组和用户,用来运行git服务:
$ groupadd git
$ useradd git -g git
2、创建证书登录
收集所有需要登录的用户的公钥,公钥位于id_rsa.pub文件中,把我们的公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
如果没有该文件创建它:
$ cd /home/git/
$ mkdir .ssh
$ chmod 755 .ssh
$ touch .ssh/authorized_keys
$ chmod 644 .ssh/authorized_keys
3、初始化Git仓库
首先我们选定一个目录作为Git仓库,假定是/home/gitrepo/runoob.git,在/home/gitrepo目录下输入命令:
$ cd /home
$ mkdir gitrepo
$ chown git:git gitrepo/
$ cd gitrepo
$ git init --bare runoob.git
Initialized empty Git repository in /home/gitrepo/runoob.git/
以上命令Git创建一个空仓库,服务器上的Git仓库通常都以.git结尾。然后,把仓库所属用户改为git:
$ chown -R git:git runoob.git
4、克隆仓库
$ git clone git@192.168.45.4:/home/gitrepo/runoob.git
Cloning into 'runoob'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.
192.168.45.4 为 Git 所在服务器 ip ,你需要将其修改为你自己的 Git 服务 ip。
这样我们的 Git 服务器安装就完成。