Git 从入门到精通,如何在项目中正确使用 Git

164 阅读11分钟

一、Git 介绍

什么是 Git

Git 是最流行的分布式版本控制系统(Distributed Version Control System,简称 DVCS)。它由 Linus Torvalds 创建,当时非常需要一个快速、高效和大规模分布式的源代码管理系统,用于管理 Linux 源代码。

由于 Linus 对几乎所有现有的源代码管理系统抱有强烈的反感,因此他决定编写自己的源代码管理系列。2005 年 4 月,Git 就诞生了。到了 2005 年 7 月,维护工作就交给了 Junio Hamano,自此他就一直在维护这个项目。

虽然最初只用于 Linux 内核,但 Git 项目迅速传播,并很快被用于管理许多其他 Linux 项目。现在,几乎所有的软件开发,尤其是在开源世界中,都是通过 Git 进行的。

Git 与 SVN 区别

  • Git 是分布式的,SVN 不是:这是 Git 和其它非分布式的版本控制系统,例如 SVN,CVS 等,最核心的区别。
  • Git 把内容按元数据方式存储,而 SVN 是按文件:所有的资源控制系统都是把文件的元信息隐藏在一个类似 .svn、.cvs 等的文件夹里。
  • Git 分支和 SVN 的分支不同:分支在 SVN 中一点都不特别,其实它就是版本库中的另外一个目录。
  • Git 没有一个全局的版本号,而 SVN 有:目前为止这是跟 SVN 相比 Git 缺少的最大的一个特征。
  • Git 的内容完整性要优于 SVN:Git 的内容存储使用的是 SHA-1 哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

Git 优势

  • 提交速度更快:  因为在 SVN 中需要更频繁地提交到中央存储库,所以网络流量会减慢每个人的速度。而使用 Git,主要在本地存储库上工作,只需每隔一段时间才提交到中央存储库。
  • 没有单点故障:  使用 SVN,如果中央存储库出现故障,则在修复存储库之前,其他开发人员无法提交他们的代码。使用 Git,每个开发人员都有自己的存储库,因此中央存储库是否损坏并不重要。开发人员可以继续在本地提交代码,直到中央存储库被修复,然后就可以推送他们的更改;
  • 可以离线使用: 与 SVN 不同,Git 可以离线工作,即使网络失去连接,也可以继续工作而不会丢失功能。

Git 安装

MacOS   Windows   Linux

MacOS:http://git-scm.com/download/mac
Windows:https://gitforwindows.org/
Linuxhttp://git-scm.com/download/linux

Git 是否安装完成

git --version

Git 命令帮助

git --help

二、基础配置

创建新仓库 init

创建新文件夹,打开,然后执行以下命令

git init

设置用户名/邮箱等信息 config

// 查看用户名/邮箱
git config user.name
git config user.email

// 配置或修改用户名/邮箱
git config --global user.name ""
git config --global user.email ""

三、基础操作

添加和提交 pull

添加到暂存区

git add <filename>
git add *

git 基本工作流程的第一步;使用如下命令以实际提交改动:

git commit -m "代码提交信息"

现在,你的改动已经提交到了 HEAD,但是还没到你的远端仓库。

推送改动 push

你的改动现在已经在本地仓库的 HEAD 中了。执行如下命令以将这些改动提交到远端仓库:

git push origin master

可以把 master 换成你想要推送的任何分支。

如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:

git remote add origin<server>

如此你就能够将你的改动推送到所添加的服务器上去了。

暂存更改 stash

假如我们正在开发迭代功能,但是还没开发完。这时有一个紧急的 bug 需要修复上线。可能就需要切换到一个 hotfix 分支去修复 bug。这时对于开发了一部分的功能创建提交是没有逻辑意义的。可以使用以下任一命令来存储修改的内容:

git stash
git stash push
git stash push -m "<stash message>"

该命令回保存所有未提交的更改并恢复到上次提交时存储库的状态。

当想再次继续开发此功能时,就可以使用以下命令检查所有存储:

git stash list

这时终端中就会显示带有时间戳的所有已经暂存的列表。可以使用以下任一命令来取回所有的更改:

git stash apply
git stash pop

apply 和 pop 之间的区别在于,pop 应用了 stash 中的更改并将其也从 stash 中删除,但 apply 即使在应用后仍将更改保留在 stash 中。

可以使用以下任一命令应用存储列表中的第 N 个存储:

git stash apply stash@{N}
git stash apply <n>

合并指定提交 cherry-pick

在不同分支之间进行代码合并时,通常会有两种情况:一种情况是需要另一个分支的所有代码变动,那么就可以直接合并(git merge),另一种情况是只需要部分代码的变动(某几次提交),这时就可以使用以下命令来合并指定的提交:

git cherry-pick <commit hash>

建议添加 -x 标志,因为它会生成标准化的提交消息,通知用户它是从哪里pick出来的:

git cherry-pick -x <commit hash>

那么这个commit hash是从哪里来的呢?可以在需要被合并的分支上执行以下命令:

git log

这时终端就会显示出所有的提交信息

检查提交 show

git show

查看贡献者

可以使用以下命令来返回每个贡献者的 commit 次数以及每次 commit 的 commit message:

git shortlog

其可以添加两个参数:

  • s:省略每次 commit 的注释,仅仅返回一个简单的统计。
  • n:按照 commit 数量从多到少的顺利对用户进行排序。

加上这两个参数之后就可以看到每个用户中的提交次数以及排名情况:

git shortlog -sn

这样就会显示出该项目所有贡献者的 commit 次数,从上到下依次减小

四、分支管理

分支 branch

分支是用来将特性开发绝缘开来的。在你创建仓库的时候,master 是“默认的”分支。在其他分支上进行开发,完成后再将它们合并到主分支上。

从远端仓库拉取到本地

git clone 

列出本地存在的分支

git branch

列出远程分支

git branch -r

列出本地和远程分支

git branch -a

切换回主分支:

git checkout master

基于远程仓库的 dev 分支,创建本地仓库的 feature/canvas 分支

git branch feature/canvas dev

修改 feature/canvas 分支名为 feature/canvas2

git branch -M feature/canvas feature/canvas2

删除本地dev分支:

git branch -d dev

推送分支到远程仓库:

git push origin <branch>

推送分支到远程仓库(将本地的分支推送到origin主机,同时指定origin为默认主机):

git push -u origin <branch>

删除远程dev分支

git push origin --delete dev

切换当前分支到 dev 分支

git checkout dev

基于当前分支创建 test 分支,并且将当前分支切换到 test 分支

git checkout -b test

同步远程分支到本地

git remote update origin --prune

日志 log

git log

<!-- 退出日志查看,涉及到 vim 命令使用 -->
英文输入法按 q 退出

回退 reset

<!-- 查看日志 -->
git log

<!-- 回退到上个版本 -->
git reset --hard HEAD^

<!-- 回退到指定版本 xxxxx代表版本id -->
git reset --hard xxxxx

<!-- 强制推送 -->
git push origin HEAD --force

<!-- 强制推送简写 -->
git push -f

注意:使用回退前应该把已修改未提交的操作提交,否则可能无法找回。

查看操作记录 reflog

回退后如果需要撤销,可以通过操作记录找到之前的id,再操作回退到最新纪录

git reflog

// 回退到指定 [id],找到对应的版本[id]填写左侧显示的数字
git reset --hard [id]

标签 tag

为软件发布创建标签是推荐的。这个概念早已存在,在 SVN 中也有。你可以执行如下命令创建一个叫做 1.0.0 的标签:

git tag 1.0.0 1b2e1d63ff

1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。可以使用下列命令获取提交 ID:

git log

你也可以使用少一点的提交 ID 前几位,只要它的指向具有唯一性。

合并远程仓库的 master 分支到当前分支

git merge origin/master

提交单个 tag

git push origin publish/1.0.0

提交所有 tag

git push origin --tags

替换本地改动

假如你操作失误(当然,这最好永远不要发生),你可以使用如下命令替换掉本地改动:

假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它:

git fetch origin
git reset --hard origin/master

五、远程操作

克隆仓库 clone

执行如下命令以克隆仓库代码:(xxx.xxx.cn代表git地址)

git clone http://xxx.xxx.cn

执行如下命令克隆指定远程分支代码:(xxx代表分支名称,xxx.xxx.cn代表git地址,project  代表创建并拉取到此文件夹)

git clone -b xxx http://xxx.xxx.cn project

如果是远端服务器上的仓库,你的命令会是这个样子:

git clone username@host:/path/to/repository

查看远程仓库信息

git remote

查看远程仓库详细信息

git remote -v

移除名字为 origin 的远程仓库

git remote remove origin

添加远程仓库

git remote origin git@github.com:x-cold/git-learning.git

工作流

你的本地仓库由 git 维护的三棵“树”组成。第一个是你的 工作目录,它持有实际文件;第二个是 暂存区(Index),它像个缓存区域,临时保存你的改动;最后是 HEAD,它指向你最后一次提交的结果。

更新与合并 push

要更新你的本地仓库至最新改动,执行:

git pull

在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。

要合并其他分支到你的当前分支(例如 master),执行:

git merge <branch>

在这两种情况下,git 都会尝试去自动合并改动。遗憾的是,这可能并非每次都成功,并可能出现冲突(conflicts)。 这时候就需要你修改这些文件来手动合并这些冲突(conflicts)。改完之后,你需要执行如下命令以将它们标记为合并成功:

git add <filename><branch>

在合并改动之前,你可以使用如下命令预览差异:

git diff <source_branch> <target_branch>

提交本地仓库当前分支到远程仓库的 master 分支

git push origin master

提交本地仓库 dev 分支到远程的 master 分支

git push origin master:dev

六、其他

实用小贴士

内建的图形化 git:

gitk

彩色的 git 输出:

git config color.ui true

显示历史记录时,每个提交的信息只显示一行:

git config format.pretty oneline

交互式添加文件到暂存区

git add -i

查看仓库每个人的代码行数

git log --format='%aN' | sort -u | while read name; do echo -en "$name	"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s
", add, subs, loc }' -; done

查看仓库总代码行数

git log  --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s
", add, subs, loc }' -

查看仓库提交总次数

git log --oneline | wc -l

仓库贡献者统计

git log --pretty=’%aN’ | sort -u | wc -l

仓库提交贡献前五

git log --pretty=’%aN’ | sort | uniq -c | sort -k1 -n -r | head -n 5

七、项目中如何使用 Git

初始化配置

// 初始化
git init

// 查看用户名/邮箱
git config user.name
git config user.email

// 配置或修改用户名/邮箱
git config --global user.name ""
git config --global user.email ""

克隆项目到指定文件夹

// 克隆指定分支代码,(xxx代表分支名称,http://xxx.xxx.cn 代表 git 地址,project 代表创建并拉取到此文件夹)
git clone -b xxx http://xxx.xxx.cn project

// 克隆远端服务器代码
git clone username@host:/path/to/repository

提交代码的 n 种方式

1、直接提交

// 提交到暂存区
git add .

// 添加注释内容
git commit -m "注释内容"

2、提交到暂存区

3、合并某个提交

常见分支

团队分支

  1. 主分支 master
  2. 开发分支 develop 或者 developer
  3. 版本分支 xxx-1.2.3.0
  4. 修复分支 patch
  5. 测试分支 testing

个人分支

  1. 个人开发分支 shubinqi-develop
  2. 个人修复分支 shubinqi-patch

合并分支

先拉取后合并 1、拉取代码(合并到哪个分支拉取哪个)

git pull

2、合并分支(<branch> 代表远端分支名称)

git merge <branch>