Git初探

一、前言

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。它与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。

Git 与 SVN 的区别:

  • SVN 是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。
  • Git 是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

集中式版本控制和分布式版本控制对比:

二、安装与配置

Git 下载地址:https://git-scm.com/downloads

2.1 更新至最新版本

yum 安装:

yum install git

克隆 git 最新版本源码(https://github.com/git/git):

git clone https://github.com/git/git.git

安装 curl-devel 包:

yum install curl-devel  

编译安装:

make configure
./configure --prefix=/usr
make make install

2.2 设置用户名和邮箱(用户标识)

当你安装 Git 后首先要做的事情是设置你的用户名称和 Email 地址。这是非常重要的,因为每次 Git 提交都会使用该信息。它被永远的嵌入到了你的提交中:

git config --global user.name "xuliangTang" 
git config --global user.email "1297441127@qq.com"

注意  git config  命令的  --global  参数,用了这个参数,表示你这台机器上所有的 Git 仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和 Email 地址。

2.3 创建版本库

版本库又名仓库(repository),你可以简单理解成一个目录,这个目录里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

通过  git init  命令可以把当前目录变成 Git 可以管理的仓库:

此时 Git 就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),并且当前目录下多了一个.git 的目录,这个目录是 Git 来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

也可以使用如下命令,把创建目录和仓库一起完成:

# 新建一个目录,将其初始化为Git代码库
git init [project-name]

2.4 克隆远程仓库

通过 git clone 命令可以将远程服务器上的仓库完全镜像一份至本地。 -b  参数设置克隆指定分支,默认为 master 分支:

# 克隆一个项目和它的整个代码历史(版本信息)
git clone [url]

三、Git 文件操作

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。GIT 不关心文件两个版本之间的具体差别,而是关心文件的整体是否有改变,若文件被改变,在添加提交时就生成文件新版本的快照,而判断文件整体是否改变的方法就是用 SHA-1 算法计算文件的校验和。

3.1 文件4种状态

  • Untracked:未跟踪,此文件在文件夹中,但并没有加入到 git 库,不参与版本控制。通过 git add 状态变为 Staged
  • Unmodify:文件已经入库,未修改,即版本库中的文件快照内容与文件夹中完全一致。这种类型的文件有两种去处,如果它被修改,而变为 Modified,如果使用 git rm 移出版本库,则成为 Untracked 文件
  • Modified:文件已修改,仅仅是修改,并没有进行其他的操作。这个文件也有两个去处,通过 git add 可进入暂存 staged 状态,使用 git checkout 则丢弃修改过,返回到 unmodify 状态,这个 git checkout 即从库中取出文件, 覆盖当前修改
  • Staged:暂存状态,执行 git commit 则将修改同步到库中,这时库中的文件和本地文件又变为一致,文件为 Unmodify 状态。执行 git reset HEAD filename 取消暂存,文件状态为 Modified

3.2 查看文件状态

通过  git status  命令可以查看文件状态:

# 查看指定文件状态
git status [filename]

# 查看所有文件状态
git status

README 文件状态为 Untracked(未跟踪),提示通过 git add 可以暂存。

3.3 添加文件与目录

工作区(Working Directory)就是你在电脑里能看到的目录。

版本库(Repository)工作区有一个隐藏目录 .git ,这个不算工作区,而是 Git 的版本库。版本库里存了很多东西,其中最重要的就是称为 stage(或者叫index)的暂存区,还有 Git 为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫 HEAD。

通过  git add  命令可以将 untracked 状态的文件添加到暂存区:

# 添加指定文件到暂存区
git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
git add [dir]

# 添加当前目录的所有文件到暂存区
git add .

3.4 查看文件修改后的差异

通过  git diff  命令可以显示工作区中的文件和暂存区中的文件的差异:

git diff [files]

---a表示修改之前的文件,+++b表示修改后的文件。

# 比较暂存区的文件与之前已经提交过的文件
git diff --cached

3.5 提交

通过  add  命令只是将文件或目录添加到了 index 暂存区,使用  commit  命令可以实现将暂存区的文件提交到本地仓库:

# 提交暂存区到仓库区
git commit -m [message]

# 提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区,跳过了add,对新文件无效
git commit -a

# 提交时显示所有diff信息
git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
git commit --amend [file1] [file2] ...

暂存区种没有了 README 文件,提交成功。

3.6 撤销修改

场景1

当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,通过命令  git checkout -- file  可以丢弃工作区的修改:

git checkout -- README

这里有两种情况:

  • 一种是 README 自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
  • 一种是 README 已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次 git commit 或 git add 时的状态。

场景2

当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改。

分两步,第一步用命令  git reset HEAD <file>  就回到了场景1:

git reset HEAD README

第二步按场景1的步骤操作。

场景3

已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

3.7 版本回退

每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在 Git 中被称为 commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个 commit 恢复,然后继续工作,而不是把几个月的工作成果全部丢失。

实际工作中,我们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,版本控制系统肯定有某个命令可以告诉我们历史记录,在 Git 中,我们用  git log  命令查看:

如果嫌输出信息太多,可以试试加上  --pretty=oneline  参数:

首先,Git 必须知道当前版本是哪个版本,在 Git 中,用  HEAD  表示当前版本,也就是最新的提交  f6ed...  ,上一个版本就是  HEAD^ ,上上一个版本就是  HEAD^^ ,当然往上100个版本写100个^比较容易数不过来,所以写成  HEAD~100 。

现在我们准备将 README 回退到上一个版本,可以使用  git reset  命令:

git reset --hard HEAD^

现在,你回退到了上一个版本。如果突然后悔了,想恢复到最新版本,但是  git status  命令已经找不到最新版本的 commit id 了怎么办?

Git 提供了命令  git reflog  记录你每一次命令:

从输出可知,之前最新的 commit id 为  f6ed188 ,现在又可以通过  git reset  命令还原回去了:

git reset --hard f6ed188

3.8 删除文件

一般情况下,你通常直接使用  rm  命令把 Git 仓库中没用的文件删了。这时 Git 知道你删除了文件,因此工作区和版本库就不一致了, git status  命令会告诉你哪些文件被删除了:

这时你有两个选择,一是确实要从版本库中删除该文件,那就用命令  git rm  删掉,并且  git commit 。

另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

git checkout -- abc

但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

另外,--cached   参数会从暂存区删除文件,而工作区则不做出改变:

# 直接从暂存区删除文件,工作区则不做出改变
git rm --cached <file>

四、远程仓库

Git 是分布式版本控制系统,同一个 Git 仓库,可以分布到不同的机器上,但开发参与者必须在同一个网络中,且必须有一个项目的原始版本,通常的办法是让一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。完全可以自己搭建一台运行Git的服务器但现在更适合的做法是使用免费的托管平台,如 Github。

同时相较于传统的代码都是管理到本机或者内网。 一旦本机或者内网机器出问题,代码可能会丢失,使用远端代码仓库将永远存在一个备份。同时也免去了搭建本地代码版本控制服务的繁琐。 云计算时代 Git 以其强大的分支和克隆功能,更加方便了开发者远程协作。

4.1 创建 SSH Key

第一步

在用户主目录下,看看有没有 .ssh 目录,如果有,再看看这个目录下有没有 id_rsa 和 id_rsa.pub 这两个文件,如果已经有了,可直接跳到下一步。如果没有,则创建:

ssh-keygen -t rsa -C "1297441127@qq.com"

然后一路回车,如果一切顺利的话,可以在用户主目录里找到 .ssh 目录,里面有 id_rsa 和 id_rsa.pub 两个文件,这两个就是 SSH Key 的秘钥对,id_rsa 是私钥,不能泄露出去,id_rsa.pub 是公钥,可以放心地告诉任何人。

第二步

登录 Github,打开 SSH and GPG keys 设置页面,点击 New SSH key,填入任意 Title,在 Key 文本框种粘贴 id_rsa.pub 文件内容:

为什么 GitHub 需要 SSH Key 呢?因为 GitHub 需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而 Git 支持 SSH 协议,所以,GitHub 只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,GitHub 允许你添加多个 Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的 Key 都添加到 GitHub,就可以在每台电脑上往 GitHub 推送了。

4.2 提交源代码到远程仓库

创建远程仓库的地址有两种:

HTTPS(推荐轻量级用户使用)

使用加密的网页访问通道读写仓库,使用用户名及密码进行鉴权

SSH(推荐资深用户或经常推送大型文件用户使用)

SSH 全称 Secure SHell 是一种网络协议,顾名思义就是非常安全的 shell,主要用于计算机间加密传输。使用加密通道读写仓库,无单次上传限制,需先设置 “账户 SSH 公钥”,完成配对验证。

目前,在 GitHub 上的这个 test 仓库还是空的,GitHub 告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到 GitHub 仓库。现在执行:

# 添加远程主机,主机名为origin,地址为git@github.com:xuliangTang/test.git
git remote add origin git@github.com:xuliangTang/test.git

添加后,远程库的名字就是 origin,这是 Git 默认的叫法,也可以改成别的。

下一步,就可以把本地库的所有内容推送到远程库上:

# 本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了,-u参数指定一个默认主机
git push -u origin master

由于远程库是空的,我们第一次推送 master 分支时,加上了  -u  参数,Git不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支关联起来,在以后的推送或者拉取时就可以简化命令。

从现在起,只要本地作了提交,就可以通过命令:

git push origin master

把本地 master 分支的最新修改推送至 GitHub。

当你第一次使用 Git 的 clone 或者 push 命令连接 GitHub 时,会得到一个警告:

这是因为 Git 使用 SSH 连接,而 SSH 连接在第一次验证 GitHub 服务器的 Key 时,需要你确认 GitHub 的 Key 的指纹信息是否真的来自 GitHub 的服务器,输入  yes  回车即可。

Git 会输出一个警告,告诉你已经把 GitHub 的 Key 添加到本机的一个信任列表里了:

这个警告只会出现一次,后面的操作就不会有任何警告了。

如果你实在担心有人冒充 GitHub 服务器,输入 yes 前可以对照 GitHub的RSA Key的指纹信息 是否与 SSH 连接给出的一致。

4.3 常用操作指令

# 下载远程仓库的所有变动
git fetch [remote]

# 显示所有远程仓库
git remote -v

# 显示某个远程仓库的信息
git remote show [remote]

# 增加一个新的远程仓库,并命名
git remote add [shortname] [url]

# 取回远程仓库的变化,并与本地分支合并
git pull [remote] [branch]

# 上传本地指定分支到远程仓库
git push [remote] [branch]

# 强行推送当前分支到远程仓库,即使有冲突
git push [remote] --force

# 推送所有分支到远程仓库
git push [remote] --all

#简单查看远程---所有仓库
git remote  (只能查看远程仓库的名字)#查看单个仓库
git remote show [remote-branch-name]

#新建远程仓库
git remote add [branchname]  [url]

#修改远程仓库
git remote rename [oldname] [newname]

#删除远程仓库
git remote rm [remote-name]

#获取远程仓库数据
git fetch [remote-name]  # 获取仓库所有更新,但不自动合并当前分支
git pull  # 获取仓库所有更新,并自动合并到当前分支

#上传数据,如git push origin master
git push [remote-name] [branch]
git fetch 命令

一旦远程主机的版本库有了更新(Git 术语叫做 commit),需要将这些更新取回本地,这时就要用到  git fetch  命令:

git fetch <远程主机名>

git fetch 命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。

默认情况下,git fetch 取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名:

git fetch <远程主机名> <分支名>

所取回的更新,在本地主机上要用  远程主机名/分支名  的形式读取。比如 origin 主机的 master,就要用  origin/master  读取。如对比本地仓库的差异:

git diff master origin/master

取回远程主机的更新以后,可以在它的基础上,使用  git checkout  命令创建一个新的分支:

git checkout -b newBrach origin/master

此外,也可以使用  git merge  命令或者  git rebase  命令,在本地当前分支上合并远程分支:

git merge origin/master
# 或者
git rebase origin/master
git pull 命令

 git pull  命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并:

git pull <远程主机名> <远程分支名>:<本地分支名>

如果远程分支是与当前分支合并,则冒号后面的部分可以省略:

git pull origin master

上面命令表示,取回 origin/master 分支,再与当前分支合并。实质上,这等同于先做 git fetch,再做 git merge。

五、Git 分支

假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

5.1 基本操作

1)查看分支

 git branch  命令会列出所有分支,当前分支前面会标一个 * 号, -r  参数查看远程分支, -a  参数查看所有分支:

2)创建并切换分支

 git checkout  命令加入  -b  参数表示创建分支并切换:

git checkout -b dev

相当于以下两条命令:

git branch dev
git checkout dev  # 如果name为-则为上一个分支

当执行 git checkout 

3)合并分支

 git merge  命令可以合并指定分支到当前分支:

git merge dev
4)删除分支

 git branch  命令加入  -d  参数表示安全删除本地仓库指定分支(需要先合并), -D 参数表示强制删除:

git branch -d dev
git branch -D dev

 git push  命令加入  --delete  参数表示删除远程仓库指定分支:

git push origin --delete dev
# 等同于
git push origin :dev

六、搭建 Git 服务器

如果我们的代码不想托管在 Github 上该怎么办呢?很简单,那就需要在自己的机器上创建一个服务,大家都来访问这个地址。准备一台 Linux 服务器,下面开始安装。

第一步:确保安装服务器上安装了 Git
第二步:创建一个 git 用户,用来运行 Git 服务
useradd git
第三步:设置 SSH 无密码登录

修改 /etc/ssh/sshd_config 配置文件,将以下内容去掉注释:

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys
第四步:创建证书登录

收集所有需要登录的用户的公钥,就是他们自己的 id_rsa.pub 文件,把所有公钥导入到  /home/git/.ssh/authorized_keys  文件里,一行一个。

第五步:初始化 Git 仓库

首先切换至 git 用户:

su - git

选定一个目录作为 Git 仓库,假定是 /home/git/server.git,在 /home/git 目录下输入命令:

git init --bare server.git 

Git 就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的 Git 仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的 Git 仓库通常都以 .git 结尾。

第六步:禁用 Shell 登录

出于安全考虑,git 用户不允许登录 Shell。执行:

usermod -s /usr/bin/git-shell git

这样,git 用户可以正常通过 ssh 使用 git,但无法登录 shell,因为我们为 git 用户指定的 git-shell 每次一登录就自动退出。

 第七步:克隆远程仓库

现在,可以通过  git clone  命令克隆远程仓库了,在各自的电脑上运行:

git clone git@server:/home/git/server.git

参考

《一个小时学会Git》:http://www.cnblogs.com/best/p/7474442.html

《Git教程》:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

原文地址:https://www.cnblogs.com/tangxuliang/p/9216735.html