Git 实战教程

01.Git 介绍

1、实验说明css

1. 内容简介html

本节为版本控制系统和 Git 的历史介绍,不包含实验操做内容。Git 实验操做的内容从第二节开始。git

 

2. 课程来源github

感谢译者 liuhui998 受权,本实验课程基于 《Git Community Book 中文版》 制做。web

 

3.课程学习说明编程

学习本课程须要有必定的Linux基础,熟悉Linux的经常使用命令。vim

 

基本用法部分的实验已经涵盖了最经常使用的 git 操做,中级用法能够简单了解,用到时再查详细文档。缓存

2、Git 诞生安全

同生活中的许多伟大事件同样,Git 诞生于一个极富纷争大举创新的年代。1991年,Linus 建立了开源的 Linux,而且有着为数众多的参与者。虽然有世界各地的志愿者为 Linux 编写代码,可是绝大多数的 Linux 内核维护工做都花在了提交补丁和保存归档的繁杂事务上(1991-2002年间)。在这期间,全部的源代码都是由 Linus 手工合并。服务器

 

由于 Linus 坚决地反对 CVS 和 SVN,这些集中式的版本控制系统不但速度慢,并且必须联网才能使用。虽然有一些商用的版本控制系统,比 CVS、SVN 好用,但那是付费的,和 Linux 的开源精神不符。

 

不过,到了 2002 年,Linux 系统已经发展了十年了,代码库之大让 Linus 很难继续经过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,因而整个项目组启用了一个商业版本的分布式版本控制系统 BitKeeper 来管理和维护代码。BitKeeper 的东家 BitMover 公司出于人道主义精神,受权Linux 社区无偿使用这个版本控制系统。

 

安定团结的大好局面在 2005 年被打破,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合做关系结束,缘由是 Linux 社区牛人汇集,开发 Samba 的Andrew 试图破解 BitKeeper 的协议,这么干的其实也不仅他一个,可是被 BitMover 公司发现了,因而 BitMover 公司收回了 Linux 社区的无偿使用权。这就迫使 Linux 开源社区( 特别是 Linux 的缔造者 Linus Torvalds )不得不吸收教训,只有开发一套属于本身的版本控制系统才不至于重蹈覆辙。

 

他们对新的系统制订了若干目标:速度、简单的设计、对非线性开发模式的强力支持(容许上千个并行开发的分支)、彻底分布式、有能力高效管理相似 Linux 内核同样的超大规模项目(速度和数据量)。自诞生于 2005 年以来,Git 日臻成熟完善,迅速成为最流行的分布式版本控制系统,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,它还有着使人难以置信的非线性分支管理系统,能够应付各类复杂的项目开发需求。2008 年,GitHub 网站上线了,它为开源项目免费提供 Git 存储,无数开源项目开始迁移至 GitHub,包括 jQuery,PHP,Ruby 等等。

 

历史就是这么偶然,若是不是当年 BitMover 公司威胁 Linux 社区,可能如今咱们就没有免费而超级好用的 Git 了。

3、版本控制系统

Linus 一直痛恨的 CVS 及 SVN 都是集中式的版本控制系统,而 Git 是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢?

 

先说集中式版本控制系统,版本库是集中存放在中央服务器的,而你们工做的时候,用的都是本身的电脑,因此要先从中央服务器取得最新的版本,而后开始工做,工做完成,再把本身的修订推送给中央服务器。这类系统,都有一个单一的集中管理的服务器,保存全部文件的修订版本,而协同工做的人们都经过客户端连到这台服务器,取出最新的文件或者提交更新。

 

 

那分布式版本控制系统与集中式版本控制系统有何不一样呢?首先,分布式版本控制系统根本没有“中央服务器”,每一个人的电脑上都是一个完整的版本库,这样,你工做的时候,就不须要联网了,由于版本库就在你本身的电脑上。既然每一个人电脑上都有一个完整的版本库,那多我的如何协做呢?比方说你在本身电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,大家俩之间只需把各自的修改推送给对方,就能够互相看到对方的修改了。

 

和集中式版本控制系统相比,分布式版本控制系统的安全性要高不少,由于每一个人电脑里都有完整的版本库,某一我的的电脑坏掉了没关系,随便从其余人那里复制一个就能够了。而集中式版本控制系统的中央服务器要是出了问题,全部人都无法干活了。

 

在实际使用分布式版本控制系统的时候,其实不多在两人之间的电脑上推送版本库的修改,由于可能大家俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。所以,分布式版本控制系统一般也有一台充当“中央服务器”的电脑,但这个服务器的做用仅仅是用来方便“交换”你们的修改,没有它你们也同样干活,只是交换修改不方便而已。

 

 

许多这类系统均可以指定和若干不一样的远端代码仓库进行交互。籍此,你就能够在同一个项目中,分别和不一样工做小组的人相互协做。你能够根据须要设定不一样的协做流程,好比层次模型式的工做流,而这在之前的集中式系统中是没法实现的。

4、相关资源

若是感兴趣能够参考更详细的 Git 资料:

 

Git 项目网站  https://git-scm.com/

Git 详细文档:Git 官方参考文档 https://git-scm.com/doc

Github 网站:使用 Git 进行版本控制的代码托管网站  https://github.com/

本实验课程中咱们将对最经常使用的 Git 操做命令进行实践,上手使用 Git 做为代码版本控制的工具。

点击实验桌面右边工具栏的 下一个实验 开始进入到 Git 的实验操做吧!

02. 基本用法(上)

1、实验说明

本节实验为 Git 入门第一个实验,能够帮助你们熟悉如何建立和使用 Git 仓库。

 

知识点

仓库配置及初始化

克隆仓库

添加更新内容到索引中及提交

比较内容

获取当前项目情况

分支建立切换合并

恢复版本及查看日志

实验环境

实验环境为 Ubuntu Linux 命令行环境,须要了解基本的 Linux 操做,若是没有使用过 Linux 的同窗,推荐先学习 Linux 基础入门 前三个实验。

2、Git 的初始化

在使用 Git进行代码管理以前,咱们首先要对 Git 进行初始化配置。

使用 Git 的第一件事就是设置你的名字和 email,这些就是你在提交 commit 时的签名,每次提交记录里都会包含这些信息。使用 git config 命令进行配置:

 

$ git config --global user.name "Scott Chacon"

$ git config --global user.email "schacon@gmail.com"

执行了上面的命令后,会在家目录(/home/shiyanlou)下创建一个叫 .gitconfig 的文件(该文件为隐藏文件,须要使用 ls -al 查看到). 内容通常像下面这样,可使用 vim 或 cat 查看文件内容:

 

$ cat ~/.gitconfig

[user]

        email = schacon@gmail.com

        name = Scott Chacon

上面的配置文件就是 Git 全局配置的文件,通常配置方法是 git config --global <配置名称> <配置的值>。

 

若是你想使项目里的某个值与前面的全局设置有区别(例如把私人邮箱地址改成工做邮箱),你能够在项目中使用 git config 命令不带 --global 选项来设置. 这会在你当前的项目目录下建立 .git/config,从而使用针对当前项目的配置。

3、得到一个Git仓库

既然咱们如今把一切都设置好了,那么咱们须要一个 Git 仓库。有两种方法能够获得它:一种是从已有的Git 仓库中 clone (克隆,复制);还有一种是新建一个仓库,把未进行版本控制的文件进行版本控制。

 3.1 Clone一个仓库

为了获得一个项目的拷贝(copy),咱们须要知道这个项目仓库的地址(Git URL)。Git 能在许多协议下使用,因此 Git URL 可能以 ssh://,http(s)://,git:// 开头。有些仓库能够经过多种协议来访问。

 

咱们在 github.com 上提供了一个名字为 gitproject 的供你们测试的公有仓库,这个仓库可使用下面方式进行 clone:

 

$ cd /home/shiyanlou/

$ git clone https://github.com/shiyanlou/gitproject

clone 操做完成后,会发现 /home/shiyanlou 目录下多了一个 gitproject 文件夹,这个文件夹里的内容就是咱们刚刚 clone 下来的代码。因为当前 gitproject 仅是测试项目,里面仅有一个 README.md 文件。

$ cd gitproject/

(master)$ ls

README.md

细心的同窗能够发如今命令提示符 $ 前面多了个 (master)。这是因为实验楼的 Linux 使用的是zsh Shell,zsh 会判断当前的目录是否有 Git 仓库,若是是的话则自动把目前所在的 Git 分支显示在提示符中。Git 分支的概念咱们会在稍后介绍。

 3.2 初始化一个新的仓库

能够对一个已存在的文件夹用下面的命令让它置于 Git 的版本控制管理之下。

 

建立代码目录 project:

 

$ cd /home/shiyanlou/

$ mkdir project

进入到代码目录,建立并初始化Git仓库:

 

$ cd project

$ git init

Git 会输出:

 

Initialized empty Git repository in /home/shiyanlou/project/.git/

经过 ls -la 命令会发现project目录下会有一个名叫 .git 的目录被建立,这意味着一个仓库被初始化了。能够进入到 .git 目录查看下有哪些内容。

 

4、正常的工做流程

Git 的基本流程以下:

建立或修改文件

使用 git add 命令添加新建立或修改的文件到本地的缓存区(Index)

使用 git commit 命令提交到本地代码库

(可选,有的时候并无能够同步的远端代码库)使用git push命令将本地代码库同步到远端代码库

 4.1 建立或修改文件

进入咱们刚才创建的 project 目录,分别建立文件 file1,file2,file3:

 

$ cd /home/shiyanlou/project

$ touch file1 file2 file3

修改文件,可使用 vim 编辑内容,也能够直接 echo 添加测试内容。

 

$ echo "test" >> file1

$ echo "test" >> file2

$ echo "test" >> file3

此时可使用 git status 命令查看当前 Git 仓库的状态:

 

$ git status

On branch master

 

Initial commit

 

Untracked files:

   (use "git add <file>...") to include in what will be committed)

 

       file1

       file2

       file3

nothing added to commit but untracked files present (use "git add" to track)

能够发现,有三个文件处于 untracked 状态,下一步咱们就须要用 git add 命令将他们加入到缓存区(Index)。

 4.2 使用 git add 加入缓存区

使用 git add 命令将新建的文件添加到缓存区:

 

$ git add file1 file2 file3

而后再次执行 git status 就会发现新的变化:

 

$ git status

On branch master

 

Initial commit

 

Changes to be committed:

    (use "git rm --cached <file>..." to unstage)

 

       new file: file1

       new file: file2

       new file: file3

你如今为 commit 作好了准备,你可使用 git diff 命令再加上 --cached 参数,看看缓存区中哪些文件被修改了。进入到 git diff --cached 界面后须要输入 q 才能够退出:

 

$ git diff --cached

若是没有--cached参数,git diff 会显示当前你全部已作的但没有加入到缓存区里的修改。

 

若是你要作进一步的修改, 那就继续作, 作完后就把新修改的文件加入到缓存区中。

 4.3 使用 git commit 提交修改

当全部新建,修改的文件都被添加到了缓存区,咱们就要使用 git commit 提交到本地仓库:

 

$ git commit -m "add 3 files"

须要使用 -m 添加本次修改的注释,完成后就会记录一个新的项目版本。除了用 git add 命令,咱们还能够用下面的 -a 参数将全部没有加到缓存区的修改也一块儿提交,但 -a 命令不会添加新建的文件。

 

$ git commit -a -m "add 3 files"

再次输入 git status 查看状态,会发现当前的代码库已经没有待提交的文件了,缓存区已经被清空。

 

至此,咱们完成了第一次代码提交,此次提交的代码中咱们建立了三个新文件。须要注意的是若是是修改文件,也须要使用 git add 命令添加到缓存区才能够提交。若是是删除文件,则直接使用 git rm 命令删除后会自动将已删除文件的信息添加到缓存区,git commit 提交后就会将本地仓库中的对应文件删除。

 

这时若是咱们但愿将本地仓库关联到远端服务器,咱们可使用 git remote 命令,不一样于刚刚的 git clone 命令,直接将远端的仓库克隆下来。

 

咱们当前的仓库是使用 git init 初始化的本地仓库,因此咱们须要将本地仓库与远程仓库关联,使用以下命令(须要修改下面的远程仓库地址为本身的仓库地址):

 

$ git remote add origin https://github.com/kinglion580/shiyanlou.git

对于上述命令而言,git remote add 命令用于添加远程主机,origin 是主机名,此处咱们能够自定义,不必定非要使用 origin,而 https://github.com/kinglion580/shiyanlou.git,是我本身的远程仓库,此处 须要替换为本身的远程仓库地址

这个时候若是本地的仓库链接到了远程Git服务器,可使用下面的命令将本地仓库同步到远端服务器:

# 须要输入仓库对应的用户名和密码

$ git push origin master

5、分支与合并

Git 的分支可让你在主线(master 分支)以外进行代码提交,同时又不会影响代码库主线。分支的做用体如今多人协做开发中,好比一个团队开发软件,你负责独立的一个功能须要一个月的时间来完成,你就能够建立一个分支,只把该功能的代码提交到这个分支,而其余同事仍然能够继续使用主线开发,你天天的提交不会对他们形成任何影响。当你完成功能后,测试经过再把你的功能分支合并到主线。

 5.1 建立分支

一个 Git 仓库能够维护不少开发分支。如今咱们来建立一个新的叫 experimental 的分支:

$ git branch experimental

运行 git branch 命令能够查看当前的分支列表,以及目前的开发环境处在哪一个分支上:

$ git branch

 experimental

* master

 5.2 切换分支

experimental 分支是你刚才建立的,master 分支是 Git 系统默认建立的主分支。星号标识了你当工做在哪一个分支下,输入 git checkout 分支名 能够切换到其余分支:

 

$ git checkout experimental

Switched to branch 'experimental'

切换到 experimental 分支,切换完成后,先编辑里面的一个文件,再提交(commit)改动,最后切换回 master 分支:

 

# 修改文件file1

$ echo "update" >> file1

# 查看当前状态

$ git status

# 添加并提交file1的修改

$ git add file1

$ git commit -m "update file1"

# 查看file1的内容

$ cat file1

test

update

# 切换到master分支

$ git checkout master

查看下 file1 中的内容会发现刚才作的修改已经看不到了。由于刚才的修改时在 experimental 分支下,如今切换回了 master 分支,目录下的文件都是 master 分支上的文件了。

 5.3 合并分支

如今能够在 master 分支下再做一些不一样的修改:

 

# 修改文件file2

$ echo "update again" >> file2

# 查看当前状态

$ git status

# 添加并提交file2的修改

$ git add file2

$ git commit -m "update file2 on master"

# 查看file2的内容

$ cat file2

test

update again

这时,两个分支就有了各自不一样的修改,分支的内容都已经不一样,如何将多个分支进行合并呢?

 

能够经过下面的 git merge 命令来合并 experimental 到主线分支 master:

 

# 切换到master分支

$ git checkout master

# 将experimental分支合并到master

$ git merge -m 'merge experimental branch' experimental

-m 参数仍然是须要填写合并的注释信息。

 

因为两个 branch 修改了两个不一样的文件,因此合并时不会有冲突,执行上面的命令后合并就完成了。

 

若是有冲突,好比两个分支都改了一个文件 file3,则合并时会失败。首先咱们在master分支上修改file3 文件并提交:

 

# 切换到master分支

$ git checkout master

# 修改file3文件

$ echo "master: update file3" >> file3

# 提交到master分支

$ git commit -a -m 'update file3 on master'

而后切换到 experimental,修改 file3 并提交:

 

# 切换到experimental分支

$ git checkout experimental

# 修改file3文件

$ echo "experimental: update file3" >> file3

# 提交到experimental分支

$ git commit -a -m 'update file3 on experimental'

切换到 master 进行合并:

 

$ git checkout master

$ git merge experimental

Auto-merging file3

CONFLICT (content): Merge conflict in file3

Automatic merge failed; fix conflicts and then commit the result.

合并失败后先用 git status 查看状态,会发现 file3 显示为 both modified,查看 file3内容会发现:

 

$ cat file3

test

<<<<<<< HEAD

master: update file3

=======

experimental: update file3

>>>>>>> experimental

上面的内容也可使用 git diff 查看,先前已经提到 git diff 不加参数能够显示未提交到缓存区中的修改内容。

 

能够看到冲突的内容都被添加到了 file3 中,咱们使用 vim 编辑这个文件,去掉 Git 自动产生标志冲突的 <<<<<< 等符号后,根据须要只保留咱们须要的内容后保存,而后使用 git add file3 和 git commit 命令来提交合并后的 file3 内容,这个过程是手动解决冲突的流程。

 

# 编辑冲突文件

$ vim file3

# 提交修改后的文件

$ git add file3

$ git commit -m 'merge file3'

 5.4 删除分支

当咱们完成合并后,再也不须要experimental时,可使用下面的命令删除:

 

$ git branch -d experimental

git branch -d只能删除那些已经被当前分支的合并的分支. 若是你要强制删除某个分支的话就用git branch –D

 5.5 撤销一个合并

若是你以为你合并后的状态是一团乱麻,想把当前的修改都放弃,你能够用下面的命令回到合并以前的状态:

 

$ git reset --hard HEAD^

# 查看file3的内容,已经恢复到合并前的master上的文件内容

$ cat file3

 5.6 快速向前合并

还有一种须要特殊对待的状况,在前面没有提到。一般,一个合并会产生一个合并提交(commit), 把两个父分支里的每一行内容都合并进来。

 

可是,若是当前的分支和另外一个分支没有内容上的差别,就是说当前分支的每个提交(commit)都已经存在另外一个分支里了,Git 就会执行一个 快速向前(fast forward)操做;Git 不建立任何新的提交(commit),只是将当前分支指向合并进来的分支。

6、Git 日志

下面咱们来学习有关 Git 日志的内容。

6.1 查看日志

git log 命令能够显示全部的提交(commit):

 

$ git log

若是提交的历史纪录很长,回车会逐步显示,输入 q 能够退出。

 

git log 有不少选项,可使用 git help log 查看,例以下面的命令就是找出全部从 "v2.5“ 开始在 fs 目录下的全部 Makefile 的修改(这个只是举例,不用操做):

 

$ git log v2.5.. Makefile fs/

Git 会根据 git log 命令的参数,按时间顺序显示相关的提交(commit)。

 6.2 日志统计

若是用 --stat 选项使用 git log,它会显示在每一个提交(commit)中哪些文件被修改了, 这些文件分别添加或删除了多少行内容,这个命令至关于打印详细的提交记录:

 

$ git log --stat

 6.3 格式化日志

你能够按你的要求来格式化日志输出。--pretty 参数可使用若干表现格式,如 oneline:

 

$ git log --pretty=oneline

或者你也可使用 short 格式:

 

$ git log --pretty=short

你也可用 medium,full,fuller,email 或 raw。 若是这些格式不彻底符合你的需求, 你也能够用 --pretty=format 参数定义格式。

 

--graph 选项能够可视化你的提交图(commit graph),会用ASCII字符来画出一个很漂亮的提交历史(commit history)线:

 

$ git log --graph --pretty=oneline

 6.4 日志排序

日志记录能够按不一样的顺序来显示。若是你要指定一个特定的顺序,能够为 git log 命令添加顺序参数。

 

按默认状况,提交会按逆时间顺序显示,能够指定 --topo-order 参数,让提交按拓扑顺序来显示(就是子提交在它们的父提交前显示):

 

$ git log --pretty=format:'%h : %s' --topo-order --graph

你也能够用 --reverse 参数来逆向显示全部提交日志。

7、小结

本节讲解了几个基本命令:

 

git config:配置相关信息

git clone:复制仓库

git init:初始化仓库

git add:添加更新内容到索引中

git diff:比较内容

git status:获取当前项目情况

git commit:提交

git branch:分支相关

git checkout:切换分支

git merge:合并分支

git reset:恢复版本

git log:查看日志

课后练习

开通 [GitHub](https://github.com) 帐号,建立练习仓库并练习一遍上述所讲的内容。

03. 基本用法(上)

1、实验说明

本节实验为 Git 入门第二个实验,继续练习最经常使用的 Git 命令。

 

知识点

对比差别

分布式的工做流程

Git 标签

实验环境

实验环境为 Ubuntu Linux 命令行环境,须要了解基本的 Linux 操做,若是没有使用过 Linux 的同窗,推荐先学习 Linux 基础入门 前三个实验。

 

实验准备

在进行该实验以前,能够先 clone 一个练习项目 gitproject :

 

$ cd /home/shiyanlou

$ git clone https://github.com/shiyanlou/gitproject

本节中的实验操做都是在该项目中完成。

2、比较内容

下面将学习如何比较提交,分支等内容。

 2.1 比较提交 - Git Diff

如今咱们对项目作些修改:

 

$ cd gitproject

# 向README文件添加一行

$ echo "new line" >> README.md

# 添加新的文件file1

$ echo "new file" >> file1

使用 git status 查看当前修改的状态:

 

$ git status

On branch master

Your branch is up-to-date with 'origin/master'.

 

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git checkout -- <file>..." to discard changes in working directory)

 

    modified:   README.md

 

Untracked files:

  (use "git add <file>..." to include in what will be committed)

 

    file1

 

no changes added to commit (use "git add" and/or "git commit -a")

能够看到一个文件修改了,另一个文件添加了。如何查看修改的文件内容呢,那就须要使用 git diff 命令。git diff 命令的做用是比较修改的或提交的文件内容。

 

$ git diff

diff --git a/README.md b/README.md

index 21781dd..410e719 100644

--- a/README.md

+++ b/README.md

@@ -1,2 +1,3 @@

 gitproject

 ==========

+new line

上面的命令执行后须要使用 q 退出。命令输出当前工做目录中修改的内容,并不包含新加文件,请注意这些内容尚未添加到本地缓存区。

 

将修改内容添加到本地缓存区,通配符能够把当前目录下全部修改的新增的文件都自动添加:

 

$ git add *

再执行 git diff 会发现没有任何内容输出,说明当前目录的修改都被添加到了缓存区,如何查看缓存区内与上次提交之间的差异呢?须要使用 --cached 参数:

 

$ git diff --cached

diff --git a/README.md b/README.md

index 21781dd..410e719 100644

--- a/README.md

+++ b/README.md

@@ -1,2 +1,3 @@

 gitproject

 ==========

+new line

diff --git a/file1 b/file1

new file mode 100644

index 0000000..fa49b07

--- /dev/null

+++ b/file1

@@ -0,0 +1 @@

+new file

能够看到输出中已经包含了新加文件的内容,由于 file1 已经添加到了缓存区。

 

最后咱们提交代码:

 

$ git commit -m 'update code'

提交后 git diff 与 git diff --cached 都不会有任何输出了。

 2.2 比较分支

能够用 git diff 来比较项目中任意两个分支的差别。

 

咱们首先建立一个新的分支 test,并在该分支上提交一些修改:

 

# 建立test分支并切换到该分支

$ git branch test

$ git checkout test

# 添加新的一行到file1

$ echo "branch test" >> file1

# 建立新的文件file2

$ echo "new file2" >> file2

# 提交全部修改

$ git add *

$ git commit -m 'update test branch'

而后,咱们查看 test 分支和 master 之间的差异:

 

$ git diff master test

diff --git a/file1 b/file1

index fa49b07..17059cd 100644

--- a/file1

+++ b/file1

@@ -1 +1,2 @@

 new file

+branch test

diff --git a/file2 b/file2

new file mode 100644

index 0000000..80e7991

--- /dev/null

+++ b/file2

@@ -0,0 +1 @@

+new file2

git diff 是一个难以置信的有用的工具,能够找出你项目上任意两个提交点间的差别。可使用 git help diff 详细查看其余参数和功能。

 2.3 更多的比较选项

若是你要查看当前的工做目录与另一个分支的差异,你能够用下面的命令执行:

 

# 切换到master

$ git checkout master

 

# 查看与test分支的区别

$ git diff test

diff --git a/file1 b/file1

index 17059cd..fa49b07 100644

--- a/file1

+++ b/file1

@@ -1,2 +1 @@

 new file

-branch test

diff --git a/file2 b/file2

deleted file mode 100644

index 80e7991..0000000

--- a/file2

+++ /dev/null

@@ -1 +0,0 @@

-new file2

你也以加上路径限定符,来只比较某一个文件或目录:

 

$ git diff test file1

diff --git a/file1 b/file1

index 17059cd..fa49b07 100644

--- a/file1

+++ b/file1

@@ -1,2 +1 @@

 new file

-branch test

上面这条命令会显示你当前工做目录下的 file1 与 test 分支之间的差异。

 

--stat 参数能够统计一下有哪些文件被改动,有多少行被改动:

 

$ git diff test --stat

 file1 | 1 -

 file2 | 1 -

 2 files changed, 2 deletions(-)

3、分布式的工做流程

 下面咱们学习 Git 的分布式工做流程。

3.1 分布式的工做流程

你目前的项目在 /home/shiyanlou/gitproject 目录下,这是咱们的 Git 仓库(repository),另外一个用户也想与你协做开发。他的工做目录在这台机器上,如何让他提交代码到你的 Git 仓库呢?

 

首先,咱们假设另外一个用户也用 shiyanlou 用户登陆,只是工做在不一样的目录下开发代码,实际工做中不太可能发生,大部分状况都是多个用户,这个假设只是为了让实验简化。

 

该用户须要从 Git 仓库进行克隆:

 

# 进入到临时目录

$ cd /tmp

# 克隆git仓库

$ git clone /home/shiyanlou/gitproject myrepo

$ ls -l myrepo

-rw-rw-r-- 1 shiyanlou shiyanlou 31 Dec 22 08:24 README.md

-rw-rw-r-- 1 shiyanlou shiyanlou  9 Dec 22 08:24 file1

这就建了一个新的 "myrepo" 的目录,这个目录里包含了一份gitproject仓库的克隆。这份克隆和原始的项目如出一辙,而且拥有原始项目的历史记录。

 

在 myrepo 作了一些修改而且提交:

 

$ cd /tmp/myrepo

 

# 添加新的文件newfile

$ echo "newcontent" > newfile

 

# 提交修改

$ git add newfile

$ git commit -m "add newfile"

myrepo 修改完成后,若是咱们想合并这份修改到 gitproject 的 git 仓库该如何作呢?

 

能够在仓库 /home/shiyanlou/gitproject 中把myrepo的修改给拉 (pull)下来。执行下面几条命令:

 

$ cd /home/shiyanlou/gitproject

$ git pull /tmp/myrepo master

remote: Counting objects: 5, done.

remote: Compressing objects: 100% (2/2), done.

remote: Total 3 (delta 0), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

From /tmp/myrepo

 * branch            master     -> FETCH_HEAD

Updating 8bb57aa..866c452

Fast-forward

 newfile | 1 +

 1 file changed, 1 insertion(+)

 create mode 100644 newfile

 

# 查看当前目录文件

$ ls                                                                                         

README.md  file1  newfile

这就把 myrepo 的主分支合并到了 gitproject 的当前分支里了。

 

若是 gitproject 在 myrepo 修改文件内容的同时也作了修改的话,可能须要手工去修复冲突。

 

若是你要常常操做远程分支(remote branch),你能够定义它们的缩写:

 

$ git remote add myrepo /tmp/myrepo

git pull 命令等同于执行两个操做: 先使用 git fetch 从远程分支抓取最新的分支修改信息,而后使用 git merge 把修改合并进当前的分支。

 

gitproject 里能够用 git fetch 来执行 git pull 前半部分的工做, 可是这条命令并不会把抓下来的修改合并到当前分支里:

 

$ git fetch myrepo

From /tmp/myrepo

 * [new branch]      master     -> myrepo/master

获取后,咱们能够经过 git log 查看远程分支作的全部修改,因为咱们已经合并了全部修改,因此不会有任何输出:

 

$ git log -p master..myrepo/master

当检查完修改后,gitproject 能够把修改合并到它的主分支中:

 

$ git merge myrepo/master

Already up-to-date.

若是咱们在 myrepo 目录下执行 git pull 会发生什么呢?

 

myrepo 会从克隆的位置拉取代码并更新本地仓库,就是把 gitproject 上的修改同步到本地:

 

# 进入到gitproject

$ cd /home/shiyanlou/gitproject

 

# 添加一行内容到newfile

$ echo "gitproject: new line" >> newfile

 

# 提交修改

$ git commit -a -m 'add newline to newfile'

[master 8c31532] add newline to newfile

 1 file changed, 1 insertion(+)

 

# 进入myrepo目录

$ cd /tmp/myrepo

 

# 同步gitproject的全部修改

$ git pull

remote: Counting objects: 6, done.

remote: Compressing objects: 100% (2/2), done.

remote: Total 3 (delta 1), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

From /home/shiyanlou/gitproject

   8bb57aa..8c31532  master     -> origin/master

Updating 866c452..8c31532

Fast-forward

 newfile | 1 +

 1 file changed, 1 insertion(+)

由于 myrepo 是从 gitproject 仓库克隆的,那么他就不须要指定 gitproject 仓库的地 址。由于 Git 把 gitproject 仓库的地址存储到 myrepo 的配置文件中,这个地址就是在 git pull 时默认使用的远程仓库:

 

$ git config --get remote.origin.url

/home/shiyanlou/gitproject

若是 myrepo 和 gitproject 在不一样的主机上,能够经过 ssh 协议来执行 clone 和pull 操做:

 

$ git clone localhost:/home/shiyanlou/gitproject test

这个命令会提示你输入 shiyanlou 用户的密码,用户密码随机,能够点击实验操做界面右侧工具栏的 SSH直连 按钮查看。

 3.2 公共 Git 仓库

开发过程当中,一般你们都会使用一个公共的仓库,并 clone 到本身的开发环境中,完成一个阶段的代码后能够告诉目标仓库的维护者来 pull 本身的代码。

 

若是你和维护者都在同一台机器上有账号,那么大家能够互相从对 方的仓库目录里直接拉所做的修改,git 命令里的仓库地址也能够是本地的某个目录名:

 

$ git clone 仓库A的路径

$ git pull 仓库B的路径

也能够是一个ssh地址:

 

$ git clone ssh://服务器/帐号/仓库名称

 3.3 将修改推到一个公共仓库

经过 http 或是 git 协议,其它维护者能够经过远程访问的方式抓取(fetch)你最近的修改,可是他们没有写权限。如何将本地私有仓库的最近修改主动上传到公共仓库中呢?

 

最简单的办法就是用 git push 命令,推送本地的修改到远程 Git 仓库,执行下面的命令:

 

$ git push ssh://服务器仓库地址 master:master

或者

 

$ git push ssh://服务器仓库地址 master

git push 命令的目地仓库能够是 ssh 或 http/https 协议访问。

 3.4 当推送代码失败时要怎么办

若是推送(push)结果不是快速向前 fast forward,可能会报像下面同样的错误:

 

error: remote 'refs/heads/master' is not an ancestor of

local  'refs/heads/master'.

Maybe you are not up-to-date and need to pull first?

error: failed to push to 'ssh://yourserver.com/~you/proj.git'

这种状况一般是由于没有使用 git pull 获取远端仓库的最新更新,在本地修改的同时,远端仓库已经变化了(其余协做者提交了代码),此时应该先使用 git pull 合并最新的修改后再执行 git push:

 

$ git pull

$ git push ssh://服务器仓库地址 master

4、Git标签

下面学习 Git 标签相关内容。

 4.1 轻量级标签

咱们能够用 git tag 不带任何参数建立一个标签(tag)指定某个提交(commit):

 

# 进入到gitproject目录

$ cd /home/shiyanlou/gitproject

 

# 查看git提交记录

$ git log

 

# 选择其中一个记录标志位stable-1的标签,注意须要将后面的8c315325替换成仓库下的真实提交内,commit的名称很长,一般咱们只须要写前面8位便可

$ git tag stable-1 8c315325

 

# 查看当前全部tag

$ git tag

stable-1

这样,咱们能够用stable-1 做为提交 8c315325 的代称。

 

前面这样建立的是一个“轻量级标签”。

 

若是你想为一个tag添加注释,或是为它添加一个签名, 那么咱们就须要建立一个 "标签对象"。

 

标签对象

git tag 中使用 -a, -s 或是 -u三个参数中任意一个,都会建立一个标签对象,而且须要一个标签消息(tag message)来为 tag 添加注释。 若是没有 -m 或是 -F 这些参数,命令执行时会启动一个编辑器来让用户输入标签消息。

 

当这样的一条命令执行后,一个新的对象被添加到 Git 对象库中,而且标签引用就指向了一个标签对象,而不是指向一个提交,这就是与轻量级标签的区别。

 

下面是一个建立标签对象的例子:

 

$ git tag -a stable-2 8c315325 -m "stable 2"

$ git tag

stable-1

stable-2

 4.2 签名的标签

签名标签可让提交和标签更加完整可信。若是你配有GPG key,那么你就很容易建立签名的标签。首先你要在你的 .git/config 或 ~/.gitconfig 里配好key。

 

下面是示例:

 

[user]

    signingkey = <gpg-key-id>

你也能够用命令行来配置:

 

$ git config (--global) user.signingkey <gpg-key-id>

如今你能够在建立标签的时候使用 -s 参数来建立“签名的标签”:

 

$ git tag -s stable-1 1b2e1d63ff

若是没有在配置文件中配 GPG key,你能够用 -u 参数直接指定。

 

$ git tag -u <gpg-key-id> stable-1 1b2e1d63ff

5、小结

本节学习了下面知识点:

 

git diff

分布式的工做流程

git tag

课后练习

使用 [GitHub](https://github.com) 帐号,建立本身的仓库并练习一遍本节所讲的内容。

 

对于初学者,若是不想深刻 git 强大的高级功能的话,学完这个实验就能够开始上手开发了,后续实验内容用到的比较少,而且理解难度大。若是仍然感兴趣,建议使用一段时间 Git 后再仔细学习后续实验,会有更好的收获。

04.挑战:初始化 Git 仓库

比赛规则

1. 仔细阅读题目描述,在实验环境中完成任务

 

2. 完成任务后点击桌面右方的提交结果按钮

 

3. 系统自动评测并给出是否经过的信息

 

挑战:初始化本地 Git 仓库

介绍

本节挑战中,咱们须要建立一个本地 Git 仓库。咱们须要设置我的的 Git 信息,包括 username 和 email。另外须要对本地 Git 仓库进行初始化操做以及增长一些项目文件。

 

须要完成的任务包括:

 

设置 Git 信息;

完成本地 Git 仓库的初始化操做;

设置关联到远程仓库;

建立 README.md 文件并进行 commit(不须要 push 到远程仓库);

目标

本地 Git 仓库目录必须为 /home/shiyanlou/HelloGit/。

远程仓库地址固定为 git@shiyanlou.com/HelloGit.git,远程版本库名称为 origin。

须要在代码目录 /home/shiyanlou/HelloGit/ 中建立 README.md 文件,文件的内容以下:

Hello World

使用 git commit 提交 README.md 文件。

因为远程仓库 git@shiyanlou.com/HelloGit.git 并不存在,因此不须要 git push 推送到远程仓库。

 

知识点

仓库初始化

代码提交

05.中级技能(上)

1、实验说明

从本节开始,咱们会介绍一些中级和高级的用法,这些用法不多用到,前面实验的内容已经知足了平常工做须要,从本节开始的内容能够简单了解,须要的时候再详细查看。

 

知识点

忽略部分文件

rebase 命令

stash 命令

Git 树名

实验环境

实验环境为 Ubuntu Linux 命令行环境,须要了解基本的 Linux 操做,若是没有使用过 Linux 的同窗,推荐先学习 Linux 基础入门 前三个实验。

 

git 配置

$ git config --global user.name "Scott Chacon"

$ git config --global user.email "schacon@gmail.com"

下载测试项目环境

经过下列命令得到 gitproject 项目环境,该项目默认只有一个文件 README.md,能够用来进行后续 git 实验:

 

$ cd /home/shiyanlou

$ git clone https://github.com/shiyanlou/gitproject

2、忽略某些文件

项目中常常会生成一些 Git 系统不须要追踪(track)的文件。典型的是在编译生成过程当中产生的文件或是编程器生成的临时备份文件。

 

固然,若是你不追踪(track)这些文件,平时能够不使用 git add 去把它们加到缓存区中,可是这样会很快变成一件烦人的事,你发现项目中处处有未追踪(untracked)的文件。这样也使 git add . 和 git commit -a 变得实际上没有用处,同时 git status 命令的输出也会有它们。

 

如何解决这些问题呢?

 

你能够在你的顶层工做目录中添加一个叫 .gitignore 的文件,来告诉 Git 系统要忽略掉哪些文件,下面是文件内容的示例。

 

以'#' 开始的行,被视为注释。忽略掉全部文件名是 foo.txt 的文件,.gitignore 的文件内容为:

 

foo.txt

忽略全部生成的 html 文件:

 

*.html

若是 foo.html 这个文件不能忽略,能够写个例外:

 

!foo.html

忽略全部 .o 和 .a 文件:

 

*.[oa]

3、rebase

假设你如今基于远程分支 origin,建立一个叫 mywork 的分支。

 

$ cd /home/shiyanlou/gitproject

$ git checkout -b mywork origin

如今咱们在这个分支作一些修改,而后生成两个提交(commit)。

 

$ vim file.txt

$ git commit

$ vim otherfile.txt

$ git commit

可是与此同时,有些人也在 origin 分支上作了一些修改而且作了提交了。这就意味着 origin 和 mywork 这两个分支各自 前进 了,它们之间 分叉 了。

 

在这里,你能够用 pull 命令把 origin 分支上的修改拉下来而且和你的修改合并;结果看起来是会出现一个新的 合并的提交 (merge commit):

 

可是,若是你想让 mywork 分支历史看起来像没有通过任何合并同样,你也许能够用 git rebase:

 

$ git checkout mywork

$ git rebase origin

这些命令会把你的 mywork 分支里的每一个提交(commit)取消掉,而且把它们临时保存为补丁(patch)(这些补丁放到 .git/rebase 目录中),而后把 mywork 分支更新到最新的 origin 分支,最后把保存的这些补丁应用到 mywork 分支上。

 

当 mywork 分支更新以后,它会指向这些新建立的提交(commit),而那些老的提交会被丢弃。 若是运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除。

 

在 rebase 的过程当中,也许会出现冲突(conflict)。在这种状况,Git 会中止 rebase 并会让你去解决冲突;在解决完冲突后,用 git-add 命令去更新这些内容的索引(Index), 而后,你无需执行 git-commit,只要执行:

 

$ git rebase --continue

这样 git 会继续应用(apply)余下的补丁。

 

在任什么时候候,你能够用 --abort 参数来终止rebase的行动,而且 mywork 分支会回到 rebase 开始前的状态。

 

$ git rebase --abort

4、交互式 rebase

你也能够选择进行交互式的 rebase。这种方法一般用于在向别处推送提交以前对它们进行重写。交互式 rebase 提供了一个简单易用的途径让你在和别人分享提交以前对你的提交进行分割、合并或者重排序。在把从其余开发者处拉取的提交应用到本地时,你也可使用交互式 rebase 对它们进行清理。

 

若是你想在 rebase 的过程当中对一部分提交进行修改,你能够在 git rebase 命令中加入 -i 或 --interactive 参数去调用交互模式:

 

$ git rebase -i origin/master

这个命令会执行交互式 rebase 操做,操做对象是那些自最后一次从 origin 仓库拉取或者向origin 推送以后的全部提交。

 

若想查看一下将被 rebase 的提交,能够用以下的 log 命令:

 

$ git log github/master..

一旦你完成对提交信息的编辑而且退出编辑器,这个新的提交及提交信息会被保存起来。

 

若是指定进行 edit 操做,git 会完成一样的工做,可是在对下一提交进行操做以前,它会返回到命令行让你对提交进行修正,或者对提交内容进行修改。

 

例如你想要分割一个提交,你须要对那个提交指定 edit 操做:

 

你会进入到命令行,撤销(revert)该提交,而后建立两个(或者更多个)新提交。假设提交 21d80a5 修改了两个文件,file1 和 file2,你想把这两个修改放到不一样的提交里。你能够在进入命令行以后进行以下的操做:

 

$ git reset HEAD^

$ git add file1

$ git commit -m 'first part of split commit'

$ git add file2

$ git commit -m 'second part of split commit'

$ git rebase --continue

交互式 rebase 的最后一个做用是丢弃提交。若是把一行删除而不是指定 pick 、squash和 edit 中的任何一个,git 会从历史中移除该提交。

5、交互式添加

交互式添加提供友好的界面去操做 Git 索引(index),同时也提供了可视化索引的能力。只需简单输入 git add -i,便可使用此功能。Git 会列出全部修改过的文件及它们的状态:

 

$ git add -i

在这个例子中,咱们能够看到有5个修改过的文件尚未被加入到索引中(unstaged),甚至能够看到每一个文件增长和减小的行数。紧接着是一个交互式的菜单,列出了咱们能够在此模式中使用的命令。

 

若是咱们想要暂存(stage)这些文件,咱们能够键入 2 或者 u 进入更新(update)模式。而后咱们能够经过键入文件的范围(本例中是1-4)来决定把哪些文件加入到索引之中。

 

What now> 2

           staged     unstaged path

  1:    unchanged        +4/-0 assets/stylesheets/style.css

  2:    unchanged      +23/-11 layout/book_index_template.html

  3:    unchanged        +7/-7 layout/chapter_template.html

  4:    unchanged        +3/-3 script/pdf.rb

  5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

Update>> 1-4

           staged     unstaged path

* 1:    unchanged        +4/-0 assets/stylesheets/style.css

* 2:    unchanged      +23/-11 layout/book_index_template.html

* 3:    unchanged        +7/-7 layout/chapter_template.html

* 4:    unchanged        +3/-3 script/pdf.rb

  5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

Update>>

若是键入回车,我会回到主菜单中,同时能够看到那些指定文件的状态已经发生了改变:

 

What now> status

           staged     unstaged path

  1:        +4/-0      nothing assets/stylesheets/style.css

  2:      +23/-11      nothing layout/book_index_template.html

  3:        +7/-7      nothing layout/chapter_template.html

  4:        +3/-3      nothing script/pdf.rb

  5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

如今咱们能够看到前4个文件已经被暂存,可是最后一个没有。基本上,这是一个更加紧凑的查看状态的方式,实质上的信息与咱们在命令行中运行 git status 是一致的:

 

$ git status

6、储藏

1.储藏

当你正在作一项复杂的工做时, 发现了一个和当前工做不相关可是又很讨厌的 bug. 你这时想先修复 bug 再作手头的工做, 那么就能够用 git stash 来保存当前的工做状态, 等你修复完 bug 后,执行反储藏(unstash)操做就能够回到以前的工做里。

 

$ git stash save "work in progress for foo feature"

上面这条命令会保存你的本地修改到储藏(stash)中, 而后将你的工做目录和索引里的内容所有重置, 回到你当前所在分支的上次提交时的状态。

 

好了, 你如今就能够开始你的修复工做了。

 

$ git commit -a -m "blorpl: typofix"

当你修复完bug后, 你能够用 git stash apply 来回复到之前的工做状态。

 

$ git stash apply

2.储藏队列

你也可屡次使用 git stash 命令, 每执行一次就会把针对当前修改的储藏(stash)添加到储藏队列中. 用 git stash list 命令能够查看你保存的储藏(stashes):

 

$ git stash list

能够用相似 git stash apply stash@{1} 的命令来使用在队列中的任意一个储藏(stashes). git stash clear 则是用来清空这个队列。

7、Git 树名

1. Git 树名

不用 40 个字节长的 SHA 串来表示一个提交(commit)或是其它 git 对象,有不少种名字表示方法。在 Git 里,这些名字就叫树名(treeish)。

 

2. Sha 短名

若是你的一个提交(commit)的 sha 名字是 980e3ccdaac54a0d4de358f3fe5d718027d96aae, git会把下面的串视为等价的:

 

980e3ccdaac54a0d4de358f3fe5d718027d96aae

980e3ccdaac54a0d4

980e3cc

只要你的sha短名(Partial Sha)是不重复的(unique),它就不会和其它名字冲突(若是你使用了5个字节以上那是很难重复的),Git 也会把sha短名(Partial Sha)自动补全。

 

3. 分支, Remote 或 标签

你可使用分支,remote 或标签名来代替 SHA 串名, 它们只是指向某个对象的指针。假设你的master 分支目前在提交(commit):980e3 上, 如今把它推送(push)到 origin 上并把它命名为标签 v1.0, 那么下面的串都会被 git 视为等价的:

 

980e3ccdaac54a0d4de358f3fe5d718027d96aae

origin/master

refs/remotes/origin/master

master

refs/heads/master

v1.0

refs/tags/v1.0

这意味着你执行下面的两条命令会有一样的输出:

 

$ git log master

$ git log refs/tags/v1.0

4. 日期标识符

Git 的引用日志(Ref Log)可让你作一些 相对 查询操做:

 

master@{yesterday}

master@{1 month ago}:

上面的第一条命令是:master 分支的昨天状态(head)的缩写。注意: 即便在两个有相同 master 分支指向的仓库上执行这条命令,可是若是这个两个仓库在不一样机器上,那么执行结果也极可能会不同。

 

5. 顺序标识符

这种格式用来表达某点前面的第 N 个提交(ref)。

 

master@{5}

上面的表达式表明着 master 前面的第 5 个提交(ref)。

 

6. 多个父对象

这能告诉你某个提交的第 N 个直接父提交(parent)。这种格式在合并提交(merge commits)时特别有用,这样就可使提交对象(commit object)有多于一个直接父对象(direct parent):

 

master^2

7. 波浪号

波浪号用来标识一个提交对象(commit object)的第 N 级嫡(祖)父对象(Nth grandparent),例如:

 

master~2

就表明 master 所指向的提交对象的第一个父对象的第一个父对象(译者:你能够理解成是嫡系爷爷)。 它和下面的这个表达式是等价的:

 

master^^

你也能够把这些标识符叠加起来, 下面这个3个表达式都是指向同一个提交(commit):

 

master^^^^^^

master~3^~2

master~6

8. 树对象指针

若是你们对以前的 Git 对象模型还有印象的话, 就记得提交对象(commit object)是指向一个树对象(tree object)的。假如你要获得一个提交对象(commit object)指向的树对象(tree object)的 sha 串名, 你就能够在 ‘树名' 的后面加上 {tree} 来获得它:

 

master^{tree}

9. 二进制标识符

若是你要某个二进制对象(blob)的 sha 串名,你能够在树名(treeish)后添加二进制对象(blob)对应的文件路径来获得它:

 

master:/path/to/file

10. 区间

最后,你能够用 .. 来指两个提交(commit)之间的区间. 下面的命令会给出你在 7b593b5 和 51bea1 之间除了 7b593b5 外的全部提交(commit)(注意:51bea1是最近的提交):

 

7b593b5..51bea1

这会包括全部从 7b593b 开始的提交(commit)。译者注:至关于 7b593b..HEAD:

 

7b593b..

8、小结

本节讲解了 git 的进阶知识,在添加索引时能够经过配置 .gitignore 文件来忽略文件,又讲解了git rebase、git stash 和 git树名。

 

课后练习

请在你本身的 GitHub 仓库上操做一遍,并深刻理解这些命令。

06. 中级技能(下)

1、实验说明

本节实验中咱们将继续学习和实践一些 Git 相关的命令。

 

知识点

追踪分支

grep 搜索

Git 的撤消操做

维护 Git

创建公有和私有仓库

实验环境

实验环境为 Ubuntu Linux 命令行环境,须要了解基本的 Linux 操做,若是没有使用过 Linux 的同窗,推荐先学习 Linux 基础入门 前三个实验。

 

git 配置

$ git config --global user.name "Scott Chacon"

$ git config --global user.email "schacon@gmail.com"

下载测试项目环境

经过下列命令得到 gitproject 项目环境,该项目默认只有一个文件 README.md,能够用来进行后续 Git 实验:

 

$ cd /home/shiyanlou

$ git clone https://github.com/shiyanlou/gitproject

2、追踪分支

在 Git 中,追踪分支是用于联系本地分支和远程分支的。 若是你在 追踪分支(Tracking Branches)上执行 推送(push)或 拉取(pull)时,它会自动推送(push)或拉取(pull)到关联的远程分支上。

 

若是你常常要从远程仓库里拉取(pull)分支到本地,而且不想很麻烦的使用 git pull 这种格式; 那么就应当使用 追踪分支(Tracking Branches)。

 

git clone 命令会自动在本地创建一个 master分支,它是 origin/master 的 追踪分支 。而 origin/master 就是被克隆(clone)仓库的 master 分支。

 

你能够在使用 git branch 命令时加上 --track 参数,来手动建立一个 追踪分支 。

 

$ git branch --track experimental origin/experimental

前提是远程仓库也有一个 experimental 仓库,由于咱们这里远程仓库没有 experimental 分支,因此会报错。

 

当你运行下命令时:

 

$ git pull experimental

它会自动从 origin 抓取(fetch)内容,再把远程的 origin/experimental 分支 合并进(merge)本地的 experimental 分支。

 

当要把修改推送(push)到 origin 时,它会将你本地的 experimental 分支中的修改推送到origin 的 experimental 分支里,而无需指定它(origin)。

3、使用 Git Grep 进行搜索

用 git grep 命令查找 Git 库里面的某段文字是很方便的。固然,你也能够用 Linux 下的 grep 命令进行搜索,可是 git grep 命令能让你不用 签出(checkout)历史文件,就能查找它们。

 

例如,你要看仓库里每一个使用 xmmap 函数的地方,你能够运行下面的命令:

 

$ git grep xmmap

若是你要显示行号,你能够添加 -n选项:

 

$ git grep -n xmmap

若是咱们想只显示文件名,咱们可使用 --name-only 选项:

 

$ git grep --name-only xmmap

咱们用 -c 选项能够查看每一个文件里有多少行 匹配内容(line matches):

 

$ git grep -c xmmap

如今, 若是咱们要查找 git 仓库里某个特定版本里的内容, 咱们能够像下面同样在命令行末尾加上标签名(tag reference):

 

$ git grep xmmap v1.5.0

咱们也能够组合一些搜索条件,下面的命令就是查找咱们在仓库的哪一个地方定义了 SORT_DIRENT:

 

$ git grep -e '#define' --and -e SORT_DIRENT

我不但能够进行与(both)条件搜索操做,也能够进行或(either)条件搜索操做:

 

$ git grep --all-match -e '#define' -e SORT_DIRENT

咱们也能够查找出符合一个条件(term)且符合两个条件(terms)之一的文件行,例如咱们要找出名字中含有 PATH 或是 MAX 的常量定义:

 

$ git grep -e '#define' --and \( -e PATH -e MAX \)

4、Git 修复操做

1. 修复未提交文件中的错误(重置)

若是你如今的 工做目录(work tree)里搞的一团乱麻,可是你如今尚未把它们提交。你能够经过下面的命令,让工做目录回到上次提交时的状态(last committed state):

 

$ git reset --hard HEAD^

这条命令会把你工做目录中全部未提交的内容清空(固然这不包括未置于版控制下的文件 untracked files)。从另外一种角度来讲, 这会让 git diff 和 git diff --cached 命令的显示法都变为空。

 

若是你只是要恢复一个文件,如 hello.rb ,你就要使用 git checkout:

 

$ git checkout -- hello.rb

这条命令把 hello.rb 从 HEAD 中 checkout 而且把它恢复成未修改时的样子。

 

2. 修复已提交文件中的错误

若是你已经作了一个 提交(commit),可是你立刻后悔了,这里有两种大相径庭的方法去处理这个问题。

 

建立一个 新的提交(commit),在新的提交里撤消老的提交所做的修改。这种做法在你已经把代码发布的状况下十分正确.

 

你也能够去修改你的 老提交(old commit)。可是若是你已经把代码发布了,那么千万别这么作,git 不会处理项目历史会改变的状况,若是一个分支的历史被改变了那之后就不能正常的合并。

 

建立新提交来修复错误

建立一个新的, 撤销(revert)了前期修改的 提交(commit)是很容易的。只要把出错的提交(commit)的名字(reference)作为参数传给命令 git revert 就能够了,下面这条命令就演示了如何撤消最近的一个提交:

 

$ git revert HEAD

这样就建立了一个撤消了上次提交(HEAD)的新提交, 你就有机会来修改新提交(new commit)里的提交注释信息。

 

你也可撤消更早期的修改, 下面这条命令就是撤销 上上次(next-to-last)的提交:

 

$ git revert HEAD^

在这种状况下,Git 尝试去撤销老的提交,而后留下完整的老提交前的版本. 若是你最近的修改和要撤销的修改有 重叠(overlap),那么就会被要求手工解决 冲突(conflicts),就像解决 合并(merge)时出现的冲突同样。

 

译者注:git revert 其实不会直接建立一个 提交(commit),只会把撤销后的文件内容放到 索引(index)里,你须要再执行 git commit 命令,它们才会成为真正的提交(commit)。

 

修改提交来修复错误

若是你刚刚作了某个提交(commit), 可是你又想立刻修改这个提交,git commit 如今支持一个叫--amend 的参数,它能让你修改刚才的这个提交(HEAD commit)。这项机制能让你在代码发布前,添加一些新的文件或是修改你的提交 注释(commit message)。

 

若是你在 老提交(older commit)里发现一个错误,可是如今尚未发布到代码服务器上,你可使用 git rebase 命令的交互模式,git rebase -i 会提示你在编辑中作相关的修改。这样其实就是让你在 rebase 的过程来修改提交。

5、维护Git

1. 保证良好的性能

在大的仓库中, git 靠压缩历史信息来节约磁盘和内存空间。

 

压缩操做并非自动进行的,你须要手动执行 git gc:

 

$ git gc

压缩操做比较耗时,你运行 git gc 命令最好是在你没有其它工做的时候。

 

2. 保持可靠性

git fsck 运行一些仓库的一致性检查,若是有任何问题就会报告。这项操做也有点耗时,一般报的警告就是 悬空对象(dangling objects)。

 

$ git fsck

悬空对象(dangling objects)并非问题,最坏的状况它们只是多占了一些磁盘空间,但有时候它们是找回丢失的工做的最后一丝但愿.

6、创建一个公共仓库

1. 创建一个公共仓库

假设你我的的仓库在目录 ~/proj,咱们先克隆一个新的“裸仓库“,而且建立一个标志文件告诉 git-daemon 这是个公共仓库:

 

$ git clone --bare ~/proj proj.git

$ touch proj.git/git-daemon-export-ok

上面的命令建立了一个 proj.git 目录, 这个目录里有一个 裸 git 仓库 —— 即只有 .git 目录里的内容,没有任何签出(checkout)的文件。

 

下一步就是你把这个 proj.git 目录拷到你打算用来托管公共仓库的主机上,你能够用 scp, rsync 或其它任何方式。

 

2. 经过 git 协议导出 git 仓库

用 Git 协议导出 Git 仓库, 这是推荐的方法。

 

若是这台服务器上有管理员,他会告诉你把仓库放在哪个目录中,而且告诉你仓库的地址 git://URL 是什么。

 

服务器上须要启动 git daemon,它默认监听在 9418 端口,默认状况下它会容许你访问全部的 Git 目录(看目录中是否有 git-daemon-export-ok 文件)。能够配置 git daemon 的启动参数来让 git-daemon 限制用户经过 Git 协议只能访问哪些目录。

 

3. 经过 http 协议导出 git 仓库

Git 协议有不错的性能和可靠性,可是若是主机上已经配好了一台 web 服务器,使用 http 协议(git over http)可能会更容易配置一些。

 

你须要把新建的 裸仓库 放到 Web 服务器 的 可访问目录 里, 同时作一些调整,以便让 web 客户端得到它们所需的额外信息:

 

$ mv proj.git /var/www/html/proj.git

$ cd proj.git

$ git --bare update-server-info

$ chmod a+x hooks/post-update

克隆的时候可使用下面的命令进行克隆:

 

$ git clone http://服务器地址/proj.git

7、创建一个私有仓库

经过 SSH 协议来访问仓库

一般最简单的办法是经过 ssh 协议访问 Git(Git Over SSH)。

 

若是你在一台机器上有了一个 ssh 账号, 你只要把 git 祼仓库 放到任何一个能够经过 ssh 访问的目录,而后能够像 ssh 登陆同样简单的使用它。假设你如今有一个仓库,而且你要把它建成能够在网上可访问的私有仓库,你能够用下面的命令,导出一个 祼仓库,而后用 scp 命令把它们拷到你的服务器上:

 

$ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git

$ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git

若是其它人也在 myserver.com 这台服务器上有 ssh 账号,那么他也能够从这台服务器上克隆(clone)代码:

 

$ git clone myserver.com:/opt/git/myrepo.git

上面的命令会提示你输入 ssh 密码或是使用 公钥(public key)。

8、小结

本节实验中咱们学习了如下的知识点:

 

追踪分支

使用 git grep 进行搜索

Git 的撤消操做(git reset、git checkout、git revert)

维护 Git(git gc、git fsck)

创建公有和私有仓库

课后练习

请本身建一个公有仓库让小伙伴能够访问并提交代码。

07. 挑战:在开发分支下完成工做

在开发者分支下完成工做

介绍

本节挑战中,咱们须要从指定地址 clone 整个工程至实验楼的环境。而后建立 dev 分支。以后咱们须要增长 README-new.md 文件,可是还想保留之前的 README.md 文件并在提交时永远忽略其修改。

 

本节挑战中要完成的任务:

 

clone 远程仓库中工程;

建立并切换至 dev 分支;

增长 README-new.md 文件,忽略 README.md 文件修改;

目标

远程仓库地址 http://github.com/shiyanlou/gitproject,请克隆该仓库到 /home/shiyanlou 目录下,仓库克隆后的目录命名保持为 gitproject,路径为 /home/shiyanlou/gitproject。

向 dev 分支提交新建的 /home/shiyanlou/gitproject/README-new.md 文件,文件内容以下:

shiyanlou development

知识点

忽略文件

切换分支

提交代码

参考来源:https://www.shiyanlou.com/courses/4

相关文章
相关标签/搜索