git学习笔记

系列学习笔记首次连载于公众号:“AInewworld”,关注了解更多~

相关教程:

很好很全的官方教程第二版(力推)

廖雪峰的官方网站

莫烦python的视频git教程

1 git基础教程

1.1 git基础

(1)git思想:直接记录快照,而非差异比较;

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这是 Git 同其他系统的重要区别。

(2)近乎所有操作都是本地执行;

在 Git 中的绝大多数操作都只需要访问本地文件和资源,不用连网。

(3)文件的三种状态

对于任何一个文件,在 Git 内都只有三种状态:

  • 已提交(committed)

    已提交表示该文件已经被安全地保存在本地数据库中了;

  • 已修改(modified)

    已修改表示修改了某个文件,但还没有提交保存;

  • 已暂存(staged)

    已暂存表示把已修改的文件放在下次提交时要保存的清单中。

三者之间的关系转换如图所示:
这里写图片描述

每个项目都有一个隐藏的 Git 目录(注:如果 git clone 出来的话,就是其中 .git 的目录;如果 git clone –bare 的话,新建的目录本身就是 Git 目录。),它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据,一般情况下绝对不要人为修改。

基本的 Git 工作流程如下:

在工作目录中修改某些文件。
对修改后的文件进行快照,然后保存到暂存区域。
提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。

1.2 git安装

更多详细参考: 安装 Git

抽出来记录下常见的安装:

(1)在 Linux 上安装
在 Ubuntu 这类 Debian 体系的系统上,可以用 apt-get 安装:

$ apt-get install git

(2)在 Mac 上安装

在 Mac 上安装 Git 有两种方式。最容易的当属使用图形化的 Git 安装工具,下载地址在:
http://sourceforge.net/projects/git-osx-installer/

(3)在 Windows 上安装

在GitHub 的页面上下载 exe 安装文件并运行:

http://msysgit.github.com/

完成安装之后,就可以使用命令行的 git 工具(已经自带了 ssh 客户端)了,另外还有一个图形界面的 Git 项目管理工具。

注:windows命令行切换盘需要/d参数 :cd /d D:

1.3 初次运行git前的配置(很重要

初试使用时,主要需要配置一些用户信息;一般在新的系统上,我们都需要先配置下自己的 Git 工作环境。配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的命令修改已有的配置。

(1)用户信息

第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

这里要修改的也就是自己的名字与邮箱;其他不变

如果用了 –global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 –global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。

其他配置

(2)文本编辑器配置

接下来要设置的是默认使用的文本编辑器。Git 需要你输入一些额外消息的时候,会自动调用一个外部文本编辑器给你用。默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置:

$ git config --global core.editor emacs

(3)查看配置信息

要检查已有的配置信息,可以使用 git config –list 命令:

$ git config --list
user.name=Scott Chacon
user.email=schacon@gmail.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...

也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样:

$ git config user.name
Scott Chacon

1.4 通过帮助文档获取使用方法

对于一个指令可以是呀git自带帮助查看使用方法。
比如,要学习 config 命令可以怎么用,运行:

$ git help config

2. git的基本使用

2.1 创建一个版本库

创建一个版本库有两种方式,一种自己新建,一种克隆已有的。

  • 在工作目录中初始化新仓库

创建一个仓库用于git管理,那么里面的文件都可以被git管理记录上,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
创建一个版本库非常简单,

(1)首先,选择一个合适的地方,创建一个空目录:

$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit

(2)通过 git init 命令把这个目录变成Git可以管理的仓库:

$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

建立好后,通过ls命令可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用 ls -ah 命令就可以看见

(3)把文件添加到版本库

我们可以新建现在我们编写一个readme.txt文件,内容如下:

Git is a version control system.
Git is free software.

一定要放到learngit目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

在这之前确保完成前面说的git前的配置,比如如果你没有注册自己的姓名与邮箱,就会出现提醒“tell me who you are”的错误.之后,

第一步,用命令git add告诉Git,把文件添加到仓库:

$ git add readme.txt

执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。

第二步,用命令git commit告诉Git,把文件提交到仓库:

$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

其中双冒号后面表示注释,这个注释还是很重要的,当你想看你的历史版本的时候,这个注释就会显示出来,所以commit添加一个明确的注释对于版本查找来说非常重要。

  • 从现有仓库克隆 (非常重要的应用)

如果复制一个开源项目,可以先把该项目的 Git 仓库复制一份出来,这就需要用到 git clone 命令。

克隆仓库的命令格式为 git clone [url]。比如,要克隆 Ruby 语言的 Git 代码仓库 Grit,可以用下面的命令:

$ git clone git://github.com/schacon/grit.git

这会在当前目录下创建一个名为grit的目录,其中包含一个 .git 的目录,用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝。如果进入这个新建的 grit 目录,你会看到项目中的所有文件已经在里边了,准备好后续的开发和使用。

如果希望在克隆的时候,自己定义要新建的项目目录名称,可以在上面的命令末尾指定新的名字:

$ git clone git://github.com/schacon/grit.git mygrit

唯一的差别就是,现在新建的目录成了 mygrit,其他的都和上边的一样。

2.2 更新仓库

  • 工作目录下面的所有文件都不外乎这两种状态:已跟踪或未跟踪。(已跟踪的文件又包括好几种状态)
  • 初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改。
  • 新建的其他项目属于未跟踪文件,既没有上次更新时的快照,也不在当前的暂存区域。

(1)检测当前文件状态
:要确定哪些文件当前处于什么状态,可以用 git status 命令。比如新建了一个test.txt,然后直接git status的结果:

D:\soft\git\learngit>git status
On branch master

No commits yet

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

        test.txt

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

可以注意两点:

  • 首先,自己建立了一个主分支 branch master;

  • 其次出现了一个未跟踪的文件 Untracked files,提醒需要跟踪。

(2)跟踪新文件

使用命令 git add 开始跟踪一个新文件。

其实 git add 的潜台词就是把目标文件快照放入暂存区域,也就是 add file into staged area,同时未曾跟踪过的文件标记为需要跟踪。这样就好理解后续 add 操作的实际意义了。

注意:运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来:

添加一个文件:

git add test.txt

假如一下有好多个文件需要添加:

git add .

(4)提交更新 重要

现在的暂存区域已经准备妥当可以提交了。在此之前,请一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。所以,每次准备提交前,先用 git status 看下,是不是都已暂存起来了,然后再运行提交命令 git commit

>> git commit -m "change1"
[master (root-commit) 0e77290] change1
 3 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 1.txt
 create mode 100644 2.txt
 create mode 100644 test.txt

记住,提交时记录的是放在暂存区域的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较。

(5)查看已暂存和未暂存的更新(查看前后之间的变化)

实际上 git status 的显示比较简单,仅仅是列出了修改过的文件,如果要查看具体修改了什么地方,可以用 git diff 命令。用 git diff –cached 查看已经暂存起来的变化:

(6)移动文件(mv)

要在 Git 中对文件改名,可以这么做:

$ git mv file_from file_to

其实,运行 git mv 就相当于运行了下面三条命令:

$ mv README.txt README
$ git rm README.txt
$ git add README

如此分开操作,Git 也会意识到这是一次改名,所以不管何种方式都一样。当然,直接用 git mv 轻便得多,不过有时候用其他工具批处理改名的话,要记得在提交前删除老的文件名,再添加新的文件名。

2.3 查看历史与状态(log与diff)

在 git 中, 每一次提交(commit)的修改, 都会被单独的保存起来. 也可以说 git 的中的所有文件都是一次次修改累积起来的. 文件好比楼房, 每个 commit 记录 了盖楼需添加或者拿走的材料. 整个施工过程也被记录了下来.

2.3.1: git log用于查看历史版本commit的信息的

比如这里历史上我进行了两次commit,那么在一个项目下进行git log:

>> D:\soft\git\learngit>git log
commit 1b6d23eaf9ad62ea9e468211c15682a6b4b242c6 (HEAD -> master)
Author: Jun <1924153192@qq.com>
Date:   Sat Nov 25 19:43:02 2017 +0800

    change in 1

commit 0e772909ce9abd01f4fa9b93642ac40db4a44cd1
Author: Jun <1924153192@qq.com>
Date:   Thu Nov 23 17:41:19 2017 +0800

    change1
  • 默认不用任何参数的话,git log 会按提交时间列出所有的更新,最近的更新排在最上面。
  • 每次信息会显示:Author是谁,Date是什么时候,以及那个时候的HEAD指向了哪里。
  • 注意这个命令只会显示commit的历时信息,比如现在你又对一个文件进行了修改,但是没有add或者没有commit,此时再执行git log不会有什么更新的。

另外git log还有许多参数可以带。详细参考链接

2.3.2: git diff命令:查看这次还没 add (unstaged) 的修改部分 和上个已经 commit 的文件有何不同

现在在上一次commit后,我修改了一下其中一个text.txt文件,添加了一行:

change in test

那么此时我还没有add,更没有commit,此时我执行git diff:

>> D:\soft\git\learngit>git diff
diff --git a/test.txt b/test.txt
index e69de29..9377178 100644
--- a/test.txt
+++ b/test.txt
@@ -0,0 +1 @@
+change in test
  • 显示我添加了一行change in test。 +为添加,-为删除。

可以通过git status来观看文件是否add了,那么假设我add的文件,但是没有commit文件,同样我想看一下差别怎么办呢?

现在我们先add一下上面那个文件:

>> D:\soft\git\learngit>git status
On branch 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:   test.txt

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

>> D:\soft\git\learngit>git add test.txt

>> D:\soft\git\learngit>git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   test.txt

那么已经 add 了这次修改, 文件变成了 “可提交状态” (staged), 我们可以在 diff 中添加参数 –cached 来查看修改:

>> D:\soft\git\learngit>git diff

>> D:\soft\git\learngit>git diff --cached
diff --git a/test.txt b/test.txt
index e69de29..9377178 100644
--- a/test.txt
+++ b/test.txt
@@ -0,0 +1 @@
+change in test
  • 可以看到,add后但是没有commit的时候,直接git diff是没有反应的,必须加上–cached才能看到差别。

2.4 回到从前的相关操作

2.4.1:修改已经commit的版本

有时候我们总会忘了什么, 比如已经提交了 commit 却发现在这个 commit 中忘了附上另一个文件.

现在假设我们刚才commit后,修改了1.txt,然后我们又去commit了一下,之后突然想起来1.txt被修改了,还没有add,那么肯定就没有被commit,这个时候我们想add后再commit,同时上一次的commit想忽略掉,可以进行下面这样:

$ git commit -m 'change in 1'
$ git add 1.txt
$ git commit --amend --no-edit   # "--no-edit": 不编辑, 直接合并到上一个 commit
$ git log --oneline # "--oneline": 每个 commit 内容显示在一行
  • “–oneline”: 每个 commit 内容显示在一行,也就是作者以及邮箱不显示。
>> D:\soft\git\learngit>git log --oneline
9c2c0fb (HEAD -> master) change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1

2.4.2: reset 将一个add后的文件回到add之前

比如现在我们修改一下1.txt,然后add一下,之后在回去add之前:

>> D:\soft\git\learngit>git add 1.txt

>> D:\soft\git\learngit>git status -s
M  1.txt  #:staged  注意此时的M为绿色,代表已经modeified了

>> D:\soft\git\learngit>git reset 1.txt
Unstaged changes after reset:
M       1.txt

>> D:\soft\git\learngit>git status -s
 M 1.txt #:unstaged 注意此时的M为红色,代表还没有modeified

2.4.3: reset 回到 commit 之前(穿梭各个历时版本之中)

在穿梭到过去的 commit 之前, 我们必须了解 git 是如何一步一步累加更改的.
这里写图片描述

每个 commit 都有自己的 id 数字号, HEAD 是一个指针, 指引当前的状态是在哪个 commit. 最近的一次 commit 在最右边, 我们如果要回到过去, 就是让 HEAD 回到过去并 reset 此时的 HEAD 到过去的位置.

现在我们把所以的文件全部add后再commit,查看一下现在有几个版本的commit了:

>> D:\soft\git\learngit>git log --oneline
42735bb (HEAD -> master) change in 1.1
9c2c0fb change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1
  • 可以看到这里有5个历史的commit
  • 最近3次我们都在改1.txt里面的文件,看一下1.txt文件的内容:

    change in 1
    change 
    test reset

    现在我们想回到上一个版本怎么办呢?两种方式:一种直接

 "HEAD^"

另外一种使用它的id号,比如前面的 bbc6d6b 这些。

>> D:\soft\git\learngit>git reset --hard 9c2c0fb
HEAD is now at 9c2c0fb change in test

>> D:\soft\git\learngit>git log --oneline
9c2c0fb (HEAD -> master) change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1
  • 可以看到head已经变化了位置;
  • 打开1.txt文件可以看到:

    change in 1
    change 

    发现里面的内容是不是也变化了,没错,回到历史版本,里面的内容是会一起变化的。

但是这样我们也发现上面的 change in 1.1也不见了,如果又想回去怎么办呢?使用 git reflog 可以查看所有的head

>> D:\soft\git\learngit>git reflog
9c2c0fb (HEAD -> master) HEAD@{0}: reset: moving to 9c2c0fb
42735bb HEAD@{1}: reset: moving to HEAD
42735bb HEAD@{2}: commit: change in 1.1
9c2c0fb (HEAD -> master) HEAD@{3}: commit (amend): change in test
9ee4d05 HEAD@{4}: commit: change in test
bbc6d6b HEAD@{5}: commit: change in 2
1b6d23e HEAD@{6}: commit: change in 1
0e77290 HEAD@{7}: commit (initial): change1

这样如果我们还想回到change in 1.1,那么直接索引他的编号即可:

>> D:\soft\git\learngit>git reset --hard 42735bb
HEAD is now at 42735bb change in 1.1

>> D:\soft\git\learngit>git log --oneline
42735bb (HEAD -> master) change in 1.1
9c2c0fb change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1

我们又再次奇迹般的回到了change in 1.1。 有了编号,我们可以穿梭到任意一个版本的文件。此时去看1.txt,它的文件内容也改变了。

2.4.4: 使得单个文件回到从前 (checkout)

之前我们使用 reset 的时候是针对整个版本库, 回到版本库的某个过去. 不过如果我们只想回到某个文件的过去, 又该怎么办呢?

其实 checkout 最主要的用途并不是让单个文件回到过去, 我们之后会继续讲 checkout 在分支 branch 中的应用, 这一节主要讲 checkout 让文件回到过去.

我们现在的版本库中有三个文件:

1.txt
2.txt
test.txt

先看一下历史状态:

>> D:\soft\git\learngit>git log --oneline
42735bb (HEAD -> master) change in 1.1
9c2c0fb change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1

我们仅仅要对 1.txt 进行回到过去操作, 回到 9c2c0fb: change in test 这一个 commit. 使用 checkout + id 9c2c0fb + – + 文件目录 1.txt, 我们就能将 1.txt 的指针 HEAD 放在这个时刻 9c2c0fb:

>> D:\soft\git\learngit>git checkout 9c2c0fb -- 1.txt

ok来看一下1.txt的内容:

change in 1
change 

发现回到了从前。看一下整个commit,发现依然在1.1的版本,唯独1.txt回到了test的版本。

D:\soft\git\learngit>git log --oneline
42735bb (HEAD -> master) change in 1.1
9c2c0fb change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1

我们在 1.txt 加上一行内容 # I went back to change test 然后 add 并 commit 1.txt:

>> D:\soft\git\learngit>git add 1.txt

>> D:\soft\git\learngit>git commit -m "1.txt went to test and add comment for 1.txt "
[master ad3b7dc] 1.txt went to test and add comment for 1.txt
 1 file changed, 1 insertion(+), 1 deletion(-)

>> D:\soft\git\learngit>git log --oneline
ad3b7dc (HEAD -> master) 1.txt went to test and add comment for 1.txt
42735bb change in 1.1
9c2c0fb change in test
bbc6d6b change in 2
1b6d23e change in 1
0e77290 change1

可以看出, 不像 reset 时那样, 我们的 change 1.1 并没有消失, 但是 1.txt 却已经回去了过去, 并改写了未来.

2.5 git的一些技巧和窍门

自动补全

下载 Git 的源代码,进入 contrib/completion 目录,会看到一个 git-completion.bash 文件。将此文件复制到你自己的用户主目录中。,并把下面一行内容添加到你的 .bashrc 文件中:

source ~/.git-completion.bash

Linux 上则复制到 /etc/bash_completion.d/ 目录中。这两处目录中的脚本,都会在 Bash 启动时自动加载。

如果在 Windows 上安装了 msysGit,默认使用的 Git Bash 就已经配好了这个自动补全脚本,可以直接使用。

在输入 Git 命令的时候可以敲两次跳格键(Tab),就会看到列出所有匹配的可用命令建议:

$ git co<tab><tab>
commit config

Git 命令别名

Git 并不会推断你输入的几个字符将会是哪条命令,不过如果想偷懒,少敲几个命令的字符,可以用 git config 为命令设置别名。来看看下面的例子:

$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

现在,如果要输入git commit 只需键入 git ci 即可。而随着 Git 使用的深入,会有很多经常要用到的命令,遇到这种情况,不妨建个别名提高效率。

用这种技术还可以创造出新的命令,比方说取消暂存文件时的输入比较繁琐,可以自己设置一下:

$ git config --global alias.unstage 'reset HEAD --'

这样一来,下面的两条命令完全等同:

$ git unstage fileA
$ git reset HEAD fileA

3. 分支

3.1 :何谓分支

很多时候我们需要给自己或者客户用一个稳定的版本库, 然后同时还在开发另外一个升级版. 自然而然, 我们会想到把这两者分开处理, 用户使用稳定版, 我们开发我们的开发版. 不过 git 的做法却不一样, 它把这两者融合成了一个文件, 使用不同的分支来管理.

分支就是在当前的项目上独立一个head指针出来,有多少个分支就有多少个独立的head,不同的分支之间可以进行不同独立的操作。相当于可以多并行化的对用一个文件进行不同的操作而不会干扰,最后再进行合并即可。

在 Git 中提交时,会保存一个提交(commit)对象,该对象包含一个指向暂存内容快照的指针,包含本次提交的作者等相关附属信息,包含零个或多个指向该提交对象的父对象指针:首次提交是没有直接祖先的,普通提交有一个祖先,由两个或多个分支合并产生的提交则有多个祖先。

通常情况下,我们不建立分支的时候,就默认在初始化的主分支master上进行的,通常我们会把 master 当作最终的版本。开发新版本或者新属性的时候, 在另外一个分支上进行, 这样就能使开发和使用互不干扰了。

3.2 :新建分支

现在有一个项目,下面有两个文件:1.txt和2.txt,其中我commit了两次,没有分支,看一下状态就是:

>> D:\soft\git\test>git log --oneline --graph
* 3c9fcdc (HEAD -> master) change two
* 164e1f8 change one
  • 注意: –graph就可以把分支图都画出来。

下面我建立一个分支,使用的命令式 git branch

>> D:\soft\git\test>git branch testing

D:\soft\git\test>git log --oneline --graph
* 3c9fcdc (HEAD -> master, testing) change two
* 164e1f8 change one
  • 可以看到,在目前第二个commit下,就有两个HEAD了,目前的HEAD是指向master的。

假如我想把HEAD切换到testing怎么办呢?此时需要使用 git checkout 命令了。

>> D:\soft\git\test>git checkout testing
Switched to branch 'testing'

>> D:\soft\git\test>git log --oneline --graph
* 3c9fcdc (HEAD -> testing, master) change two
* 164e1f8 change one
  • 可以看到切换后会有提示,同时HEAD也变化了。

现在来说说分支有什么用,说之前我们先看看我的两个文件中的内容:

1.txt:
change 1-1
change 1-2

2.txt:
change 2-1
change 2-2

好,现在我们相在testing分支上修改内容,同时master住分支上先不变,相当于master是一个1.0版本在运行着,而我们正在研发2.0版本,待研发好了再合并到master上去。

简单修改下1.txt的内容如下:

change 1-1
change 1-2
change in testing branch 

然后看一下状态:

>> D:\soft\git\test>git status
On branch testing
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:   1.txt

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

>> D:\soft\git\test>git add .

>> D:\soft\git\test>git commit -m "change in tesing"
[testing c01b5b8] change in tesing
 1 file changed, 2 insertions(+), 1 deletion(-)

>> D:\soft\git\test>git log --oneline --graph
* c01b5b8 (HEAD -> testing) change in tesing
* 3c9fcdc (master) change two
* 164e1f8 change one
  • 很简单,首先我们在分支tesing下面,提醒我修改了文件没add,add完了之后看一下状态还是在分支tesing,没问题。

下面关键来了 ,我们说我们在testing分支下操作的文件,理论上如果我们切换到主分支master下的时候,里面的1.txt的文件没有变化,下面来看一下,先切换分支:

>> D:\soft\git\test>git checkout master
Switched to branch 'master'

之后我们打开了 1.txt 发现如下:

change 1-1
change 1-2

神奇吧,加的 change in testing branch 内容并没有显示出来。

好了假设我们在testing分支上开发完了,想合并到branch上去,可以如下:

>> D:\soft\git\test>git checkout master
Already on 'master'

>> D:\soft\git\test>git merge testing
Updating 3c9fcdc..c01b5b8
Fast-forward
 1.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
  • 首先我们需要切换到master上(当然前面已经做这件事了);
  • 其次使用合并命令(merge)
  • 合并完了我们可以看到说1.txt添加了内容。这个时候我们再去打开看一下 1.txt 发现:

    change 1-1
    change 1-2
    change in testing branch 

    内容更改了吧。

为了把分支合并过程显示出来,可以如下添加 –no-ff 参数:

>> D:\soft\git\test>git merge --no-ff -m "merge testing to master" testing
Merge made by the 'recursive' strategy.
 1.txt | 1 +
 1 file changed, 1 insertion(+)

>> D:\soft\git\test>git log --oneline --graph
*   51ebeb2 (HEAD -> master) merge testing to master
|\
| * 5ff866d (testing) change three
|/
* c01b5b8 change in tesing
* 3c9fcdc change two
* 164e1f8 change one
  • 可以看到,这个分支的过程都显示出来了,怎么分支的,在哪里合并到,都有。

当该testing分支没有使用价值的时候可以删除它,使用 git branch -d 参数,如下:

>> D:\soft\git\test>git branch -d testing
Deleted branch testing (was 5ff866d).

再来看一下状态:

>> D:\soft\git\test>git log --oneline --graph
*   51ebeb2 (HEAD -> master) merge testing to master
|\
| * 5ff866d change three
|/
* c01b5b8 change in tesing
* 3c9fcdc change two
* 164e1f8 change one
  • 和上面的相比可以发现,testing分支的head已经没有了。

3.3 :分支存在冲突怎么办

有时候合并操作并不会如此顺利。如果在不同的分支中都修改了同一个文件的同一部分,Git 就无法干净地把两者合到一起。比如上面这个例子,我在新建了testing分支后,在testing分支中我去修改了1.txt,但是有个人在这个master分支中也跑去修改了1.txt,那么再去合并就会出现问题,下面模拟一下,实现我们建个分支testing,然后在testing修改1.txt,在master分支中也修改1.txt,之后合并看看:

先切换到testing分支,然后人为修改下1.txt
>> D:\soft\git\test>git checkout testing
Switched to branch 'testing'
>> D:\soft\git\test>git add .
>> D:\soft\git\test>git commit -m "change in testing 1.1"

再切换到master分支,然后人为修改下1.txt
>> D:\soft\git\test>git checkout master
Switched to branch 'master'

>> D:\soft\git\test>git add .

>> D:\soft\git\test>git commit -m "change in master"
[master 8cc6917] change in master
 1 file changed, 2 insertions(+), 1 deletion(-)

>> D:\soft\git\test>git merge --no-ff -m "merge testing to master" testing
Auto-merging 1.txt
CONFLICT (content): Merge conflict in 1.txt
Automatic merge failed; fix conflicts and then commit the result.
  • Git 作了合并,但没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以用 git status 查阅:

    >> D:\soft\git\test>git status
    On branch master
    You have unmerged paths.
      (fix conflicts and run "git commit")
      (use "git merge --abort" to abort the merge)
    
    Unmerged paths:
      (use "git add <file>..." to mark resolution)
    
            both modified:   1.txt
    
    no changes added to commit (use "git add" and/or "git commit -a")

    任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出 。Git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。这个时候我们去打开1.txt,可以看到此文件包含类似下面这样的部分:

change 1-1
change 1-2
change in testing branch 
change in testing branch 
<<<<<<< HEAD
change in master branch 
=======
change in testing branch 
>>>>>>> testing

这个时候你需要手动去调整了。比如如果这里我把两者都保留,也就是testing分支里面的修改和master里面的修改都保留,这个时候我们只需要下面这三行全部手动删除即可。

<<<<<<< HEAD
=======
>>>>>>> testing

在解决了所有文件里的所有冲突后,运行 git add 将把它们标记为已解决状态。

>> D:\soft\git\test>git add .

>> D:\soft\git\test>git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

        modified:   1.txt

可以看到冲突基本解决。我们再来看下状态:

>> D:\soft\git\test>git commit -m "change all"
[master 49f7c12] change all

>> D:\soft\git\test>git log --oneline --graph
*   49f7c12 (HEAD -> master) change all
|\
| * 965c38c (testing) change in tesing 1
* | 8cc6917 change in master
|/
*   51ebeb2 merge testing to master
|\
| * 5ff866d change three
|/
* c01b5b8 change in tesing
* 3c9fcdc change two
* 164e1f8 change one
  • 注意几个变化:可以看到在master和testing分支上,各有一个*, 也就是输出的第三行和第四行,这就表示的是你在master和testing上都修改过文件,最后再合并到一起的。

3.4 :分支的管理

对于分支,还有一些其他方面的管理方法,下面简单列举一下:

  • 直接使用git branch 命令,不加任何参数的话,它会给出当前所有分支的清单;

    $ git branch
      iss53
    * master
      testing

    其中带*号的为当前所在分支;

  • 加上 -v 参数,可以查看各个分支最后一个提交对象的详细信息。

  • 想要查看那些分支已经被合并了,可以用 –merged ; 查看哪些没有被合并 –no-merged ;这样做的好处可以把那些已经合并的子分支给删除掉,避免冗余。删除命令为: git branch -d 。有的分支没有合并,那么如果用 -d 删除时会报错,这个时候想强制删除,可以用大写D, -D 参数。

3.5 :利用分支进行开发工作的一般流程

本节内容的官方教程讲的很好,很通用,值得了解。这里摘取一下。

现在我们已经学会了新建分支和合并分支,可以(或应该)用它来做点什么呢?在本节,我们会介绍一些利用分支进行开发的工作流程。而正是由于分支管理的便捷,才衍生出了这类典型的工作模式,你可以根据项目的实际情况选择一种用用看。

长期分支

由于 Git 使用简单的三方合并,所以就算在较长一段时间内,反复多次把某个分支合并到另一分支,也不是什么难事。也就是说,你可以同时拥有多个开放的分支,每个分支用于完成特定的任务,随着开发的推进,你可以随时把某个特性分支的成果并到其他分支中。

许多使用 Git 的开发者都喜欢用这种方式来开展工作,比如仅在 master 分支中保留完全稳定的代码,即已经发布或即将发布的代码。与此同时,他们还有一个名为 develop 或 next 的平行分支,专门用于后续的开发,或仅用于稳定性测试 — 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布。

本质上我们刚才谈论的,是随着提交对象不断右移的指针。稳定分支的指针总是在提交历史中落后一大截,而前沿分支总是比较靠前(见图)。

这里写图片描述

或者把它们想象成工作流水线,或许更好理解一些,经过测试的提交对象集合被遴选到更稳定的流水线:
这里写图片描述

你可以用这招维护不同层次的稳定性。某些大项目还会有个 proposed(建议)或 pu(proposed updates,建议更新)分支,它包含着那些可能还没有成熟到进入 next 或 master 的内容。这么做的目的是拥有不同层次的稳定性:当这些分支进入到更稳定的水平时,再把它们合并到更高层分支中去。再次说明下,使用多个长期分支的做法并非必需,不过一般来说,对于特大型项目或特复杂的项目,这么做确实更容易管理。

特性分支

在任何规模的项目中都可以使用特性(Topic)分支。一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支。可能你在以前的版本控制系统里从未做过类似这样的事情,因为通常创建与合并分支消耗太大。然而在 Git 中,一天之内建立、使用、合并再删除多个分支是常见的事。

我们在上节的例子里已经见过这种用法了。我们创建了 iss53 和 hotfix 这两个特性分支,在提交了若干更新后,把它们合并到主干分支,然后删除。该技术允许你迅速且完全的进行语境切换 — 因为你的工作分散在不同的流水线里,每个分支里的改变都和它的目标特性相关,浏览代码之类的事情因而变得更简单了。你可以把作出的改变保持在特性分支中几分钟,几天甚至几个月,等它们成熟以后再合并,而不用在乎它们建立的顺序或者进度。

现在我们来看一个实际的例子。请看图下,由下往上,起先我们在 master 工作到 C1,然后开始一个新分支 iss91 尝试修复 91 号缺陷,提交到 C6 的时候,又冒出一个解决该问题的新办法,于是从之前 C4 的地方又分出一个分支 iss91v2,干到 C8 的时候,又回到主干 master 中提交了 C9 和 C10,再回到 iss91v2 继续工作,提交 C11,接着,又冒出个不太确定的想法,从 master 的最新提交 C10 处开了个新的分支 dumbidea 做些试验。

这里写图片描述

现在,假定两件事情:我们最终决定使用第二个解决方案,即 iss91v2 中的办法;另外,我们把 dumbidea 分支拿给同事们看了以后,发现它竟然是个天才之作。所以接下来,我们准备抛弃原来的 iss91 分支(实际上会丢弃 C5 和 C6),直接在主干中并入另外两个分支。最终的提交历史将变成图下这样:
这里写图片描述

请务必牢记这些分支全部都是本地分支,这一点很重要。当你在使用分支及合并的时候,一切都是在你自己的 Git 仓库中进行的 — 完全不涉及与服务器的交互。

4. github的简单使用

github是一个在线项目托管平台,里面有众多别人开源的项目,非常好。

有时候我们想把我们的项目不光存在本地,还想存在网上,或者共享出来和大家一起使用或者修改之类的,就可以使用github了。国内也有一个在线托管平台 码云,也很强大,提供很多服务。

下面简单介绍如何把自己的项目上传到github上去。

传上去首先得拥有一个账户,这个就不说了,注册一个即可。接着我们需要在github主页新建一个库:

这里写图片描述

比如这里新建一个后就是这样,这里根据提醒,在自己的本地客服端输入下面的两行,前提是客户端上当前目录要索引到你的项目目录下

  • 第一行就是表面你要上传的网络地址;
  • 第二行就是把你的项目推到github上去;

这里还是以前几节的那个例子为例,首先我们来看看这个例子:

这里写图片描述

运行这两句以后,你的项目就推到了github上了,在github上刷新一下看看:

这里写图片描述

可以看到有了。因为我们推送的是整个项目,而且可以看到推送的是主分支master(注意项目中的次分支,比如这里有testing分支是没有没推上去的),而且项目里面的隐藏文件夹 .git 也会被推上去。需要注意的是,电脑如果是第一次推的话,可能会弹出让你输入github的账号密码信息,输入进去就好了(以windows系统为例的)。

这里写图片描述

推送分支上去

假设我们想把testing分支也推上去怎么办呢,直接再推送一遍。

>> D:\soft\git\test>git push -u origin testing
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/jungrea/helloworld.git
 * [new branch]      testing -> testing
Branch 'testing' set up to track remote branch 'testing' from 'origin'.

这里写图片描述

这个时候我们去看下面的内容,可以看到,分支不同,内容是不一样的,完全和本地的是一模一样。

查看本地编辑的历时信息

同时我们可以在网页上观看我们commit的过的历史信息,像下面这样:

这里写图片描述

然后可以看到:
这里写图片描述

删除一个项目

如果我们想删除一个已经建立的项目,可以如下:
这里写图片描述

之后拉倒最下面,删除即可,点击后输入库的名字,就删除了。再去查看,就发现没有这个项目了。
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值