【Git】简单使用

 

转载:https://blog.csdn.net/weixin_38256474/article/details/82835603

1、预备知识
一个人:Linus Torvalds(全名:Linus Benedict Torvalds,译作 林纳斯·本纳第克特·托瓦兹),Linux内核的发明者,现受聘于 开放源代码开放实验室(OSDL),1969-12-28生于芬兰-赫尔辛基市,毕业于赫尔辛基大学。一个牛逼的低调人物。《时代》周刊20世纪100位最重要人物第15位(比尔盖茨才第17位哦)。21岁时完成Linux第一个内核雏形。就是下方这位老帅哥,脱发不严重:

在这里插入图片描述
一个概念:版本控制系统(Version Control System,VCS),版本控制,是对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理,是软件配置管理的核心思想之一。其最主要的功能是 追踪文件的变更。

常用的CVS、SVN(开源的),ClearCase(IBM,收费的)、VSS(微软) ,都是集中式版本控制系统;

一个工具:Git,是分布式版本控制系统(一个工具),还有类似Git的Mercurial和Bazaar,本人没用过。大名鼎鼎的Git,由声名远扬的Linus Torvalds开发。源于2005年 开发Linux Kernel的免费使用BitKeeper(BK,一个商业版本控制系统)权限被取消,促使Linus Torvalds开发出自个的项目版本管理工具。听说从无到有,花了10天。

Git优点:
① 版本库本地化,支持离线提交(不像集中式VCS联网才能工作),相对独立不影响协同开发(强调个体,适合分布式开发)。

每个开发者都拥有自己的版本控制库,可在自己的版本库上任意的执行提交代码、创建分支等行为。例如,开发者认为自己提交的代码有问题,因为版本库是自己的,可进行回滚历史、反复提交、归并分支,而并不会影响到其他开发者。

② 更少的“仓库污染”。

Git 对于每个工程只会产生一个.git目录,这个工程所有的版本控制信息都在这个目录中,不会像SVN那样在每个目录下都产生.svn目录。

③ 把内容按元数据方式存储,完整克隆版本库。

所有版本信息位于.git目录中,它是处于我们机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签、分支、版本记录等。

④ 支持快速切换分支方便合并,比较合并性能好。

在同一目录下即可切换不同的分支,方便合并,且合并文件速度比SVN快。

⑤ 分布式版本库,无单点故障,内容完整性好。

内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

Git缺点:
学习周期长些;不符合常规思维?;代码保密性稍差,一旦开发者把整个库clone下来就可完全公开所有代码和版本信息,即安全性低(当然适合于开源嘛)。

PS:GitHub,一个面向开源及私有软件项目的远程托管平台(即开源代码库、版本控制系统),因为只支持Git作为唯一的版本库格式进行托管,故名GitHub。(类似的还有GitLab,BitBucket,GitCafe。国内有码云、CODING(码市)、阿里云 Code、百度效率云、华为CodeHub)

2008年4月10日正式上线;2018年6月4日被微软75亿美金收购。它托管了海量git库,各种开源代码。
2、实操
2.1 Git下载安装

官方下载地址,目前最新版本2.19.0(2018-09-10)。

安装完成后,打开Git Bash(它是一个终端仿真器(Terminal Emulator)),在命令行窗口如下命令进行设置:

Administrator@Cchen-PC MINGW64 /
$ git config --global user.name "Your Name"

Administrator@Cchen-PC MINGW64 /
$ git config --global user.email "[email protected]"

    1
    2
    3
    4
    5

上述git config命令中的--global参数,表示该电脑上所有Git仓库都将使用这项配置;也可以对某个仓库指定不同的用户名和Email。
2.2 创建版本库(repository)

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

如D盘下testGit文件夹是项目所在之处。
2.2.1 初始化Git仓库

Administrator@Cchen-PC MINGW64 /
$ cd D:\testGit

Administrator@Cchen-PC MINGW64 /d/testGit
$ git init
Initialized empty Git repository in D:/testGit/.git/

    1
    2
    3
    4
    5
    6

git init命令作用是将项目所在目录变成Git可管理的仓库,自动新增一个.git目录,它是用于跟踪管理版本库。将包含如下文件夹和文件:
在这里插入图片描述
2.2.2 添加项目文件到版本库

1、git add <文件名>命令将项目文件添加到仓库:可反复多次使用,也可添加多个文件(以空格隔开)

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add readme.txt

    1
    2

注:
①例中D:testGit/readme.txt 是随意编写一个文件。
②所有版本控制系统,只能跟踪文本文件的改动,如html、各种程序代码、txt文件,且文本编码建议使用标准的UTF-8;而无法跟踪二进制文件,如图片、视频、word文档等,但可跟踪文件大小变动。
③git add . 提交新文件(new)、被修改文件(modified),不包括被删除文件(deleted);
git add -u 提交被修改文件(modified)、被删除文件(deleted),不包括新文件(new);
git add -A 提交所有变化。

2、将文件提交到仓库:git commit -m "备注信息"

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "my first git commit:readme.txt"
[master (root-commit) 9679b2f] my first git commit:readme.txt
 1 file changed, 1 insertion(+)
 create mode 100644 readme.txt

    1
    2
    3
    4
    5

-m命令后是此次提交的说明,可输入有意义的内容,以便从历史记录找到改动记录。
git commit命令执行成功后会打印消息:1 file changed 一个文件被改动;1 insertion(+) 插入了两行内容。
2.3 本地仓库Git管理
2.3.1 查看仓库状态和被修改内容

随意修改一下readme.txt文件。
查看仓库当前状态信息:git status

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   readme.txt

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

Changes not staged for commit 译作 未提交的更改 提交
no changes added to commit 译作 没有更改添加到提交中
其中,modified: readme.txt 表示被修改的文件名。

查看仓库被修改的具体内容:git diff <被修改文件>

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 60a3fa0..13e615b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1 +1,2 @@
-我的学习Git之路!
\ No newline at end of file
+我的学习Git之路!
+我现在修改了。
\ No newline at end of file

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

2.3.2 版本回退

1、显示提交日志(历史):git log命令

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git log
commit a0ee5d135cff50f4c2d077a6754ad93ba4cf2bed
Author: Yourname
Date:   Tue Sep 25 22:25:38 2018 +0800

    Third changed.

commit 71d82e993205194bb216cc565a7444b900bd6a96
Author: Yourname
Date:   Tue Sep 25 21:33:31 2018 +0800

    second commit

commit 9679b2ff35572ca3b31bbf9bccf5e08e738451b5
Author: Yourname
Date:   Tue Sep 25 20:57:36 2018 +0800

    my first git commit:readme.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

git log命令将显示从时间轴上最近到最远的提交日志。其中commit 71d82e99...是commit id(版本号),id是由SHA1计算出的一个十六进制表示的数字。

git log命令加上参数--pretty=oneline将简化打印信息:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git log --pretty=oneline
a0ee5d135cff50f4c2d077a6754ad93ba4cf2bed Third changed.
71d82e993205194bb216cc565a7444b900bd6a96 second commit
9679b2ff35572ca3b31bbf9bccf5e08e738451b5 my first git commit:readme.txt

    1
    2
    3
    4
    5

2、版本回退:git reset命令,加上--hard参数,这个操作比较危险。
在Git中:
参数     含义
HEAD     当前版本
HEAD^     上一个版本
HEAD^^     上上一个版本
HEAD~n     上n个版本

例如:回退到上一个版本

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git reset --hard HEAD^
HEAD is now at 71d82e9 second commit

    1
    2
    3

3、查看当前版本的内容:cat <文件名>

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ cat readme.txt
我的学习Git之路!
我现在修改了。

    1
    2
    3
    4
    5

根据commit id还可在上述例中已回退的版本回到“未来”的某个版本,如例中第三个版本:其中commit id不必全部输入(通常是前6位即可),输入前几位就OK。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git reset --hard a0ee5d135cff50f4c2d077a6754ad93ba4cf2bed
HEAD is now at a0ee5d1 Third changed.

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ cat readme.txt
我的学习Git之路!
我现在修改了。
我的第3次修改!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

4、查看命令历史:git reflog命令,可用于确定回到未来的某个版本

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git reflog
a0ee5d1 HEAD@{0}: reset: moving to a0ee5d135cff50f4c2d077a6754ad93ba4cf2bed
71d82e9 HEAD@{1}: reset: moving to HEAD^
a0ee5d1 HEAD@{2}: commit: Third changed.
71d82e9 HEAD@{3}: commit: second commit
9679b2f HEAD@{4}: commit (initial): my first git commit:readme.txt

    1
    2
    3
    4
    5
    6
    7

2.3.3 工作区、暂存区、本地仓库
名称     描述
工作区     代码编写、修改所在的目录,如我的例中D:/testGit
暂存区     git add命令将本地修改添加到暂存区(即stage或index)
本地仓库     git commit命令将暂存区中的内容提交到本地仓库(也即 当前分支)

在执行git init命令 初始化Git版本库(即创建Git版本库)时,Git将自动创建唯一一个master分支。git commit命令就是向master分支上提交更改。

例:再次修改(第4次)readme.txt文件;在工作区新增LICENSE文件(内容随意)

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ touch LICENSE # 新建LICENSE文件

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ vi LICENSE # 编辑LICENSE文件

    1
    2
    3
    4
    5

查看此时仓库状态:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   readme.txt

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

        LICENSE

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

上述打印告知:readme.txt被修改;LICENSE文件的状态是Untracked,译作 无足迹。即没被git add到仓库过。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add LICENSE

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        new file:   LICENSE
        modified:   readme.txt
Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "Fourth change for readme.txt and add LICENSE."
[master 089ee82] Fourth change for readme.txt and add LICENSE.
warning: LF will be replaced by CRLF in LICENSE.
The file will have its original line endings in your working directory.
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 LICENSE

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

在这里插入图片描述
2.3.4 管理和撤销修改、删除文件
1、管理修改

根据上一小节流程图可知:Git跟踪并管理的是实质是修改,而非文件。即每一次的修改(如新增文件、新增/删除一行、更改内容)都得git add到暂存区,并git commit。

也就是说 如果没有把某次修改git add到暂存区,那么在执行git commit时将不会跟踪到这次修改的。

也换句话说,git commit只对暂存区负责。

2、撤销修改

现在,对D:/testGit/readme.txt进行一次修改(如新增一行)。

在修改完成后,如果反悔了不想要这次修改,有两种方案:
方案1:在readme.txt删掉新增的那行;不过执行git status能看到文件被修改过。
方案2:git check -- readme.txt命令执行撤销修改;

根据上一小节的流程图可知,可应用在如下场景:
场景①:工作区修改了内容,想放弃工作区的修改时,运用git checkout -- filename命令;
场景②:工作区修改了内容,而且还git add到了暂存区,想放弃修改,分两步:1)git reset HEAD filename命令回到①;2)按场景①操作。
场景③:(没有推送到远程库)想放弃撤销本次提交,运用版本回退命令 git reset。

3、删除文件

删除也是一个修改操作。
例:在工作区新增一个文件abc.txt;并提交到Git仓库。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add abc.txt

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "add abc.txt"
[master 7533102] add abc.txt
 1 file changed, 1 insertion(+)
 create mode 100644 abc.txt

    1
    2
    3
    4
    5
    6
    7
    8

场景:要删除abc.txt文件。
方案1:直接在目录中手动删除abc.txt;
方案2:rm命令删除abc.txt:rm abc.txt;
方案3:git rm命令从版本库中删除abc.txt文件,接着git commit提交。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git rm abc.txt
rm 'abc.txt'

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "remove abc.txt"
[master 1578051] remove abc.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 abc.txt

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git status
On branch master
nothing to commit, working directory clean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

对于方案1和方案2,Git将知道我们删除了abc.txt文件,这样,工作区 跟版本库就形成不一致了。git status 将显示出哪些文件删除了。
这样,因为版本库中还有abc.txt,在误删情况下,可用git checkout -- abc.txt命令恢复到最新版本。

对于方案3,文件将从版本库中删除,工作区中也删除。运行git status命令不会打印哪些文件被删除了。
当然,方案3的替代做法是:手动删除文件后,接着使用git rm filename和git add filename,效果是一样的。
2.4 远程仓库
这是Git与SVN(集中式版本控制系统)等的最大区别。

Git是分布式版本控制系统,同一个Git仓库,可分布到不同的机器上。
在这里插入图片描述
某台机器拥有原始版本库,其他机器都可克隆此原始版本库,每台机器上的版本库是一样的,无主次之分。
2.4.1 GitHub账户

可自行搭建一运行Git的服务器、也可使用GitHub(一个Git仓库托管平台),有了远程仓库,就不用担心充当服务器的机器坏了。每个人都可从远程仓库克隆版本库到自己机器上,并可各自将自己的提交推送到远程仓库,也可以从远程仓库拉取他人的提交。

1、在GitHub注册账号;
2、创建SSH Key。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ ssh-keygen -t rsa -C "[email protected]"

    1
    2

一直回车,使用默认值。我的Win10将在C:\Users\Administrator目录下新增.ssh目录,里头有id_rsa、id_rsa.pub两个文件,这是SSH Key的密钥对,前者是私钥、后者是公钥。

3、登录GitHub,Setting,SSH and GPG keys,SSH key / Add new:完成添加。
在这里插入图片描述
这步操作的目的:由于本地Git仓库 与远程GitHub之间的传输是通过SSH加密的,GitHub根据公钥就能确定推送的提交是我推送的(而不是别人)。Git支持SSH协议。

GitHub允许添加多个Key,毕竟可能我有多台机器。
2.4.2 创建远程仓库

场景:创建一个本地Git仓库 和 一个在GitHub上的Git仓库,两者远程同步,GitHub上的仓库既可作为备份,也可用于他人协作。

1、创建远程仓库
在这里插入图片描述
如此在GitHub上创建了一个空的testGit仓库。并将得到一个远程仓库URL。

2、添加到远程仓库(关联一个远程仓库):git remote add origin <远程仓库URL>

git remote add origin https://github.com/czy0905/testGit.git

    1

参数origin,表示远程仓库名字,这是Git约定成俗的,一看到它就知道是远程仓库。
在这里插入图片描述
PS:由于我没有添加SSH key到当前GitHub,所以出现上述需要输入GitHub账户名和密码。以及上述github URL是用的https协议(每次得输入口令。慢一些),而不是ssh协议(git://,速度快)。

3、将本地仓库所有内容推送到远程仓库:git push
下方是将当前分支master推送到远程仓库。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git push -u origin master
Username for 'https://github.com':
Counting objects: 17, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (10/10), done.
Writing objects: 100% (17/17), 1.45 KiB | 0 bytes/s, done.
Total 17 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote:      https://github.com//testGit/pull/new/master
remote:
To https://github.com//testGit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

此时刷新远程仓库URL,就可看到远程仓库的内容和本地仓库一样了:
在这里插入图片描述
今后,只要本地仓库进行了提交,就可以通过git push命令将本地master分支推送到GitHub。
2.4.3 远程仓库clone

先在GitHub创建一个新的仓库,名为gitLearn。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ cd D:\gitLearn

Administrator@Cchen-PC MINGW64 /d/gitLearn
$ git clone [email protected]:/gitLearn

    1
    2
    3
    4
    5

上述用的这种URL:[email protected]:/gitLearn,SSH协议的。
也可用:https://github.com//gitLearn,https协议。
在这里插入图片描述
2.5 分支管理
场景:多人协同开发某个应用程序。
2.5.1 创建和合并分支

在创建、切换、删除分支操作上,Git都可快速完成。

每一次git commit提交,Git都将它们串成一条时间线,这条时间线 即为一个分支。上述例中到目前为止,只有一条时间线,这条分支称为 主分支,即master分支。HEAD严格意义上不是指向提交,它指向当前分支;master才是指向提交。

master分支是一条线,Git利用master指向最新的提交;再用HEAD指向master,就可确定当前分支、以及当前分支的提交点。
在这里插入图片描述
每提交一次,master分支将向前移动一步。随着不断提交,master分支的时间线将越来越长。

1、创建分支

当创建一个新的分支时(如:dev),Git将新建一个指针 dev,指向master相同的提交点,再将HEAD指向dev(表示当前分支在dev上):
在这里插入图片描述
Git创建一个分支是极速的:增加一个分支的dev指针,更改HEAD指向;而工作区文件不用产生任何变化。

此时,对工作区的修改、提交都将针对dev分支。例如:新提交一次,dev指针往前移动一步,但master指针是不变的。
在这里插入图片描述
对应的创建分支git命令:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout -b dev
Switched to a new branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$

    1
    2
    3
    4
    5
    6

git checkout -b dev命令表示创建dev分支,并切换到dev分支。等价于下方两个命令:

git branch dev # 创建分支
git checkout dev # 切换到分支

    1
    2

查看当前分支命令:git branch,它会列出所有分支,并在当前分支前标 *。

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git branch
* dev
  master

    1
    2
    3
    4

此时,可在dev分支上提交了,如对readme.txt修改1次。提交:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git commit -m "work on dev branch.Fifth commit."
[dev fbb9f20] work on dev branch.Fifth commit.
 1 file changed, 2 insertions(+), 1 deletion(-)

    1
    2
    3
    4

现在dev分支工作已完成,可切换至master分支:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

    1
    2
    3
    4

在切换到master分支后,用cat readme.txt命令查看文件内容,可发现刚才对其的修改是看不见的。原因是:对其修改的提交是dev分支进行的,而master分支此刻的提交点并未变动。如下图所示:
在这里插入图片描述

2、合并分支

接着上例:在dev分支上工作完成了,需将dev分支的工作成果合并到master分支上。Git需要做的是直接将master指向dev的当前提交即可。这就是合并分支。
在这里插入图片描述

合并分支命令:git merge,它用于合并指定分支到当前分支。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git merge dev
Updating 1578051..fbb9f20
Fast-forward
 readme.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

    1
    2
    3
    4
    5
    6

Fast-foward 表示为快速模式合并。
此时,再用cat readme.txt命令查看文件内容,就可发现和dev分支的最新提交是一样的了。

如果现在不需要dev分支了,可使用删除分支命令:git branch -d <分支名称>。在删除分支后,查看分支情况,将看不到dev分支了。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git branch -d dev
Deleted branch dev (was fbb9f20).

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git branch
* master

    1
    2
    3
    4
    5
    6
    7

2.5.2 解决分支冲突

案例:
1 新建并切换分支branch_01:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout -b branch_01
Switched to a new branch 'branch_01'

    1
    2
    3

2 修改readme.txt文件,新增一行;
3 在branch_01分支上提交,然后切换回master分支:

Administrator@Cchen-PC MINGW64 /d/testGit (branch_01)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (branch_01)
$ git commit -m "create branch_01.change readme.txt last line."
[branch_01 82aee8f] create branch_01.change readme.txt last line.
 1 file changed, 2 insertions(+), 1 deletion(-)

Administrator@Cchen-PC MINGW64 /d/testGit (branch_01)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

上述打印Your branch is ahead of 'origin/master' by 1 commit.提示:当前本地的master分支 比远程仓库的master分支要超前一个提交。
4 在master分支上将readme.txt文件中新增一行(注意 此时打开的文件是原来在master上的内容,并非在branch_01上的内容),然后提交:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "change readme.txt on master."
[master 3c3830a] change readme.txt on master.
 1 file changed, 2 insertions(+), 1 deletion(-)

    1
    2
    3
    4
    5
    6
    7

现在,master分支、branch_01分支各自分别有新的提交,如下图所示:
在这里插入图片描述
此时,Git是无法执行Fast-forward快速模式合并的。只能试图将各自的修改合并起来,但这样合并就很可能会有冲突:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git merge branch_01
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

Administrator@Cchen-PC MINGW64 /d/testGit (master|MERGING)
$

    1
    2
    3
    4
    5
    6
    7
    8

合并失败!!注意观察显示分支的地方变成了 master|MERGING
Git打印提示:fix conflicts and then commit the result.即解决冲突后再提交。

对于上述这种案例,是很容易产生的。
git status命令可告知冲突的文件:

Administrator@Cchen-PC MINGW64 /d/testGit (master|MERGING)
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add ..." to mark resolution)

        both modified:   readme.txt

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

查看readme.txt文件内容:变成了这样。

Administrator@Cchen-PC MINGW64 /d/testGit (master|MERGING)
$ cat readme.txt
我的学习Git之路!
我现在修改了。
我的第3次修改!
我是第4次修改的内容的一行。
在dev分支上操作。第5次修改。
<<<<<<< HEAD
我是在创建branch_01分支后,在master分支上新增的一行哦。
=======
我在创建branch_01分支。
>>>>>>> branch_01

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

Git使用<<<<<<<、=======、>>>>>>>来标记不同分支的内容。

解决冲突:
1、修改并保存此时的readme.txt,即修改成所希望的内容。
2、提交:

Administrator@Cchen-PC MINGW64 /d/testGit (master|MERGING)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (master|MERGING)
$ git commit -m "conflict fixed."
[master 7540926] conflict fixed.

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git branch
  branch_01
* master

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

使用git log命令可查看分支合并情况。git log --graph可查看分支合并图。

现在,master分支和branch_01分支将如下图所示:
在这里插入图片描述

如果不需要branch_01分支了,可将其删除。
2.5.3 分支管理策略

上一小节的Fast-forward快速模式合并的方案下,若删除了分支,也将会丢掉分支信息。

而强制禁用Fast-forward快速模式,Git将在merge时生成一个新的commit,从而可在分支历史上看出分支信息。

1、–no-ff模式
下方介绍--no-ff模式的git merge:
①仍然创建并切换dev分支:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout -b dev
Switched to a new branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)

    1
    2
    3
    4
    5

②修改readme.txt文件,并提交一个新的commit:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git commit -m "branch strategy."
[dev dbd4013] branch strategy.
 1 file changed, 1 insertion(+)

    1
    2
    3
    4
    5
    6
    7

③切换回master分支,然后合并dev分支,使用--no-ff参数(即表示禁用Fast-forward):

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

上述合并会同时创建一个新的commit,因此加上-m参数,以便将commit描述写入。

合并后可使用git log命令查看分支历史:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git log --graph --pretty=oneline --abbrev-commit
*   33e86b1 merge with no-ff
|\
| * dbd4013 branch strategy.
|/
*   7540926 conflict fixed.
|\
| * 82aee8f create branch_01.change readme.txt last line.
* | 3c3830a change readme.txt on master.
|/
* fbb9f20 work on dev branch.Fifth commit.
* 1578051 remove abc.txt
* 7533102 add abc.txt
* 089ee82 Fourth change for readme.txt and add LICENSE.
* a0ee5d1 Third changed.
* 71d82e9 second commit
* 9679b2f my first git commit:readme.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

上方在不使用Fast-forward模式下,merge过程如下图所示:
在这里插入图片描述

2、分支策略

在实际开发过程中,应该按照一些基本原则进行分支管理:

首先、master分支本应是非常稳定的,即仅用来发布新版本,平常不可在master分支上工作;

平时工作都应在dev分支上,即dev分支是不稳定的。例如:发布1.0版本时,将dev分支合并到master分支上,在master分支发布1.0版本。

开发团队的每个人都在dev分支上工作,每个人都有自己的分支,每个人只须在完成自己的任务时往dev分支上合并即可。如下图所示:
在这里插入图片描述

在合并分支时,加上--no-ff参数就能进行普通模式合并,合并后的历史有分支,可看出曾经做过分支;而Fast-forward合并是看不出曾经做过合并。
2.5.4 修复Bug的分支

在这里插入图片描述
在实际软件开发过程中,可能经常会有bug。每个bug都可通过一个新的临时分支进行修复,修复之后,合并分支,然后删除临时分支。

场景:研发经理发来一个修复bug代号为crash_001的任务,我立马创建一个issue-crash_001分支来修复该bug。但是,当前在dev分支上的工作进行到60%,无法提交。而bug须马上修复。

例:现在,切换到dev分支;并修改readme.txt文件和新建一个hello.py文件。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout dev
Switched to branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git status
On branch dev
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   readme.txt

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

        hello.py

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

解决方案:Git提供了一个stash功能,它能将当前工作现场“贮藏”起来,等修复bug后可恢复现场继续工作:
①git stash命令

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git stash
Saved working directory and index state WIP on dev: dbd4013 branch strategy.
HEAD is now at dbd4013 branch strategy.

    1
    2
    3
    4

此时,使用git status命令查看工作区,是干净的,可放心地创建分支来修复bug。
②确定在哪个分支上修复bug,如需在master分支上修复bug,就从master创建临时分支:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout -b issue-crash_001
Switched to a new branch 'issue-crash_001'

Administrator@Cchen-PC MINGW64 /d/testGit (issue-crash_001)
$

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

③修复bug。例如 在readme.txt修改某行内容。然后提交:

Administrator@Cchen-PC MINGW64 /d/testGit (issue-crash_001)
$ git add readme.txt

Administrator@Cchen-PC MINGW64 /d/testGit (issue-crash_001)
$ git commit -m "fix bug 001"
[issue-crash_001 d3aa70c] fix bug 001
 1 file changed, 1 insertion(+), 1 deletion(-)

    1
    2
    3
    4
    5
    6
    7

④bug修复后,切换到master分支,完成合并;最后删除issue-crash_001分支:

Administrator@Cchen-PC MINGW64 /d/testGit (issue-crash_001)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git merge --no-ff -m "merged bug fix 001" issue-crash_001
Merge made by the 'recursive' strategy.
 readme.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

⑤回到dev分支继续完成未剩余的工作。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git checkout dev
Switched to branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git status
On branch dev
nothing to commit, working directory clean

    1
    2
    3
    4
    5
    6
    7
    8

上述可看到工作区是干净的。运用git stash list命令可查看刚才的工作现场存在何处:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git stash list
stash@{0}: WIP on dev: dbd4013 branch strategy.
stash@{1}: WIP on dev: dbd4013 branch strategy.

    1
    2
    3
    4

⑥恢复工作现场。上述可看到工作现场虽然还在,但是需要恢复一下,有两个方法:
方法一:git stash apply命令用于恢复。不过在恢复后,stash内容并不会删除,需用git stash drop命令进行删除。
方法二:直接用git stash pop命令,恢复的同时,将stash内容也删除。

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git stash pop
On branch dev
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        new file:   hello.py

Dropped refs/stash@{0} (e84310d7ddd38ea0f53e01230e3b5d4e0ebbdd58)

    1
    2
    3
    4
    5
    6
    7
    8
    9

此时,再用git stash list命令,将看不到stash内容了。可多次stash,在恢复时,可先用git stash list查看,后恢复指定的stash,使用git stash apply stash@{0}。

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git stash list
stash@{0}: WIP on dev: dbd4013 branch strategy.

    1
    2
    3

2.5.5 开发新功能的分支

接到一个开发应用程序新功能的任务,名为Like(点赞功能),不过这个项目是带实验性质的,不一定将来会公开上线,需要进行一段时间验证。

因此,当然不能在主分支上进行,每添加一个新功能,就新建一个feature分支,在这开发,完成后,合并,最后删除feature分支。

①首先、创建新的feature-Like分支,并切换到feature-Like分支;

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout -b feature-Like
Switched to a new branch 'feature-Like'

Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)

    1
    2
    3
    4
    5

②开发新功能(即新增like.py),完成;
③添加、提交:

Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)
$ git add like.py

Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)
$ git status
On branch feature-Like
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        new file:   like.py


Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)
$ git commit -m "add new feature of Like"
[feature-Like 005dec4] add new feature Like
 1 files changed, 1 insertions(+)
 create mode 100644 like.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

④两种情况:
情况1:新功能Like确定了要公开发布。那么:
切回dev分支,合并,删除feature-Like分支:

Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)
$ git checkout dev
Switched to branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git merge --no-ff -m "merged new feature of Like" feature-Like
Merge made by the 'recursive' strategy.
 like.py | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 like.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

情况2:新功能Like取消,不发布了。得就地删除。那么:
切回dev分支

Administrator@Cchen-PC MINGW64 /d/testGit (feature-Like)
$ git checkout dev
Switched to branch 'dev'

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git branch -d feature-Like
error: The branch 'feature-Like' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-Like'.

    1
    2
    3
    4
    5
    6
    7
    8

失败了!提示feature-Like分支还未被合并,如果删除,将丢失掉修改;如果强行删除,需使用-D参数(大写的)。

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git branch -D feature-Like
Deleted branch feature-Like (was 005dec4).

    1
    2
    3

2.5.6 多人协作:推送和抓取分支

当从远程仓库clone时,实质是Git自动将本地master分支与远程master分支对应起来。远程仓库的默认名称为origin。
查看远程仓库信息:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git remote -v
origin  https://github.com//testGit.git (fetch)
origin  https://github.com//testGit.git (push)

    1
    2
    3
    4

上述打印提示可抓取、推送的origin URL。当然,若没有推送权限,是看不到push URL的。

1、推送分支
推送分支,即将某分支上的所有本地提交推送到远程仓库。推送时,需指定本地分支,从而Git会自动将该分支推送到远程仓库对应的远程分支上。

场景1:推送master分支到远程仓库

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git push origin master
Username for 'https://github.com':
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (20/20), 1.94 KiB | 0 bytes/s, done.
Total 20 (delta 7), reused 0 (delta 0)
remote: Resolving deltas: 100% (7/7), done.
To https://github.com//testGit.git
   1578051..69e6c1c  master -> master

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

查看URL:
https://github.com//testGit.git,它是主分支。

场景2:推送其他分支(如dev分支)到远程仓库

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git push origin dev
Username for 'https://github.com':
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 386 bytes | 0 bytes/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
remote:
remote: Create a pull request for 'dev' on GitHub by visiting:
remote:      https://github.com//testGit/pull/new/dev
remote:
To https://github.com//testGit.git
 * [new branch]      dev -> dev

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

查看URL:
https://github.com//testGit/tree/dev,它是子分支,默认这种格式。

不过,并不是非得把本地分支往远程仓库上推送,一般性原则:

    master分支是主分支,需时刻保持与远程仓库同步;
    dev分支是开发分支,项目团队成员都在此分支上工作,因此需与远程仓库同步;
    bug分支只用于在本地修复bug,无需推送到远程仓库,除非领导要看修复了几个bug;
    feature分支是新功能开发分支,是否推送到远程仓库,取决于该功能是否与团队成员合作开发。

2、抓取分支

在多人协作时,团队成员一般都会往master、dev分支上推送各自的修改。

模拟一个团队成员(名叫 大雕),即在另一台PC(将SSH Key添加到GitHub)、或同一电脑另一个目录下clone:
选择后者,在D盘新建一个otherTestGit目录,然后:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ cd d:/otherTestGit

Administrator@Cchen-PC MINGW64 /d/otherTestGit
$ git clone https://github.com//testGit.git
Cloning into 'testGit'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 40 (delta 11), reused 39 (delta 10), pack-reused 0
Unpacking objects: 100% (40/40), done.
Checking connectivity... done.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

默认情况下,大雕在clone完成后,只能看到本地master分支。

Administrator@Cchen-PC MINGW64 /d/otherTestGit
$ cd /d/otherTestGit/testGit

Administrator@Cchen-PC MINGW64 /d/otherTestGit/testGit (master)
$ git branch
* master

    1
    2
    3
    4
    5
    6

现在,大雕要在dev分支上进行开发工作,则必须创建远程仓库origin的dev分支到本地:

Administrator@Cchen-PC MINGW64 /d/otherTestGit/testGit (master)
$ git checkout -b dev origin/dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'

    1
    2
    3
    4

接着,大雕就可以在dev分支上进行开发了(如对like.py文件增加了一些代码)。

然后,将dev分支push到远程仓库:

Administrator@Cchen-PC MINGW64 /d/otherTestGit/testGit (dev)
$ git push origin dev
Username for 'https://github.com':
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 362 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com//testGit.git
   6bdc675..4fd2a19  dev -> dev

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

大雕已完成 往origin/dev分支推送提交。而我(cc)也对like.py文件作了某些修改,并想推送到远程仓库:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git add like.py

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git commit -m "changed like.py file by cc."
[dev 8e8b399] changed like.py file by cc.
 1 file changed, 1 insertion(+), 1 deletion(-)

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git push origin dev
Username for 'https://github.com':
To https://github.com//testGit.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'https://github.com//testGit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

失败了!error。提示有其他人的最新提交 与我试图推送的提交之间有冲突。Git提示的解决方案是:先用git pull将最新的提交从origin/dev上抓取下来;然后在本地合并,解决冲突,再推送。

首先、设置指定本地dev分支 与远程仓库origin/dev分支的链接:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git branch --set-upstream-to=origin/dev dev
Branch dev set up to track remote branch dev from origin.

    1
    2
    3

然后、运行git pull命令:注意dev|MERGING这个变化。

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git pull
Auto-merging like.py
CONFLICT (content): Merge conflict in like.py
Automatic merge failed; fix conflicts and then commit the result.

Administrator@Cchen-PC MINGW64 /d/testGit (dev|MERGING)
$

    1
    2
    3
    4
    5
    6
    7
    8

接着、手动解决冲突(即修改like.py成所希望的内容):

最后、添加、提交,push:

Administrator@Cchen-PC MINGW64 /d/testGit (dev|MERGING)
$ git add like.py

Administrator@Cchen-PC MINGW64 /d/testGit (dev|MERGING)
$ git commit -m "fix conflict of like.py file."
[dev c5c07a9] fix conflict of like.py file.

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git push origin dev
Username for 'https://github.com':
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 730 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To https://github.com//testGit.git
   4fd2a19..c5c07a9  dev -> dev

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

现在,在远程仓库就可以看到大雕和我(cc)对like.py文件合并后的内容了。

综上所述,多人协作的工作模式:

    试图使用git push origin 推送自己的修改;
    如果推送失败,则多半是因为远程仓库分支比你的本地分支更加新,需要先使用git pull试图合并(若提示There is no tracking information for the current branch.,则表示本地分支与远程分支的链接关系未创建。需使用git branch --set-upstream=origin/ 进行创建);
    如果合并有冲突,则得先解决冲突,并在本地提交;
    没有冲突、或解决冲突后,再使用git push origin 推送就能成功。

2.6 标签(tag)管理

发布某一个版本时,先在版本库中创建一个tag,如此,就唯一确定了创建tag时刻的版本。tag是版本库的一个快照。将来无论何时,取某个tag的版本,即将创建该tag时刻的历史版本取出来。

Git的tag虽然是版本库的快照,但其实它是指向某个commit的指针(跟分支很像),不过分支可以移动,tag不可移动。创建、删除tag都是可瞬间完成的。

场景:前面commit id是像28859fc...一长串的数字和字母。不好记。tag可以是一个有意义(易记住)的名称(如v1.0),它跟某个commit绑在一起。
2.6.1 创建标签(tag)

在Git中创建tag很简单。
首先、切换到需要创建tag的分支上:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git branch
* dev
  feature-Like
  issue-crash_001
  master

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

然后、创建一个tag:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag v1.0

    1
    2

默认情况下,tag创建在最新提交的commit上的。

接着、可查看所有tag:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag
v1.0

    1
    2
    3

如何在指定的某个历史commit上创建tag?
①切换到需要创建tag的分支上:

Administrator@Cchen-PC MINGW64 /d/testGit (dev)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

    1
    2
    3
    4

②找到历史提交的commit id:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git log --pretty=oneline --abbrev-commit
69e6c1c merged bug fix 001
d3aa70c fix bug 001
33e86b1 merge with no-ff
dbd4013 branch strategy.
7540926 conflict fixed.
...

    1
    2
    3
    4
    5
    6
    7
    8

③例如对merged bug fix 001这次提交创建tag,对应的commit id是69e6c1c:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag v0.9 69e6c1c

    1
    2

④查看tag:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag
v0.9
v1.0

    1
    2
    3
    4

注意:tag不是按时间顺序列出,而是按字母顺序。可用git show 查看tag信息。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git show v0.9
commit 69e6c1cca6c80604411a83ed86e8748569182d7c
Merge: 33e86b1 d3aa70c
Author: chenchen
Date:   Wed Sep 26 22:36:29 2018 +0800

    merged bug fix 001

    1
    2
    3
    4
    5
    6
    7
    8

创建带有说明的tag,-a参数指定tag名,-m参数指定说明文字:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag -a v0.1 -m "version 01. released." 3c3830a

    1
    2

查看说明文字:git show

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git show v0.1
tag v0.1
Tagger: chenchen
Date:   Thu Sep 27 16:01:05 2018 +0800

version 01. released.

commit 3c3830a3edca753544a34e178a96771af22657fa
Author: chenchen
Date:   Wed Sep 26 18:37:40 2018 +0800

    change readme.txt on master.

diff --git a/readme.txt b/readme.txt
index 25dc014..1fe74d9 100644
...

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

PS:tag总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个tag。
2.6.2 操作标签(tag)

如果tag创建错了,也可删除:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag -d v0.1
Deleted tag 'v0.1' (was c2a7da2)

    1
    2
    3

创建的tag只存储在本地,并不会自动推送到远程仓库。所以,创建错了的tag可在本地安全删除。

如果要推送某个tag到远程仓库,可使用git push origin

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git push origin v1.0
Username for 'https://github.com':
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com//testGit.git
 * [new tag]         v1.0 -> v1.0

    1
    2
    3
    4
    5
    6

一次性推送全部尚未推送到远程仓库的本地标签:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git push origin --tags
Username for 'https://github.com':
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com//testGit.git
 * [new tag]         v0.9 -> v0.9

    1
    2
    3
    4
    5
    6

删除在远程仓库的tag,步骤:
首先、在本地删除:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git tag -d v0.9
Deleted tag 'v0.9' (was 69e6c1c)

    1
    2
    3

然后、在远程仓库删除:

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git push origin :refs/tags/v0.9
Username for 'https://github.com':
To https://github.com//testGit.git
 - [deleted]         v0.9

    1
    2
    3
    4
    5

查看远程仓库的tag:点开【release】按钮就能看到。
2.7 自定义Git

Git除了user.name和user.email这两个配置项。还有很多的配置项。

简单举例:
1、文本编辑器。Git默认调用环境变量editor定义的值作为文本编辑器。如果没有定义,会调用vi进行创建、编辑、以及标签信息。使用core.editor改变默认编辑器:

git config --global core.editor emacs

    1

2、分页器。比如运行如log、diff命令时,可设置该项为more(默认为 less)、也可设置为空字符串(即不管输出多少,都会一页显示所有内容):

git config --global core.pager ''

    1

3、着色。可输出加上颜色。
打开默认所有默认终端的着色:true、false、always

git config --global color.ui true

    1

等等,还有很多的配置项,可让工作更高效。
2.7.1 忽略特殊文件

场景:在开发过程中,如某些文件(如保存了数据库密码的配置文件)需放在工作区,但是不能提交这些文件。

解决方案:
1、在工作区根目录创建一个特殊的名为.gitignore文件。当然,它本身就会被放入版本库中,才起作用。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ touch .gitignore

    1
    2

2、编辑.gitignore文件,即将需要忽略(不提交)的文件名编入。可参考GitHub官方提供的模板。如此,在提交时,Git将自动忽略这些文件,不会添加到版本管理中。

忽略文件的原则:

    操作系统自动生成的文件;
    编译生成的中间文件、可执行文件,如Python编译产生的.pyc文件;
    带有敏感信息的配置文件,如存放密码的配置文件。

另外,.gitignore忽略规则有优先级、匹配语法等。可参考文章。

3、将.gitignore提交到Git、push到远程仓库。

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git add .gitignore

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git commit -m "add .gitignore"
[master 49999e5] add .gitignore
 1 file changed, 2 insertions(+)
 create mode 100644 .gitignore

Administrator@Cchen-PC MINGW64 /d/testGit (master)
$ git push origin master
Username for 'https://github.com':
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 325 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com//testGit.git
   69e6c1c..49999e5  master -> master

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

PS:
情况1:如果某个文件被.gitignore忽略了,add不到Git。但确实需要add该文件,可用git add -f 强制add到Git。
情况2:如果发现.gitignore写得有文件(如某个规则写错了),可用git check-ignore命令进行检查。
2.7.2 配置别名和文件

1、配置别名

比如git status命令,容易输错。可简化命令为git st。这就用到配置别名。其中,--global表示全局参数,即这台机器上所有Git仓库下都有效。

$ git config --global alias.st status

    1

还有一些可简写如下:也可以简写成别的名。

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

    1
    2
    3

再如:将暂存区的修改撤销掉(unstage),重新放回工作区的命令 git reset HEAD 。该命令简写配置如下

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

    1

简写后是 git unstage

接着例如:显示最后一次提交信息,可简写如下

$ git config --global alias.last 'log -1'

    1

简写后是 git last。

最狠的配置别名:git lg

$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

    1

2、配置文件

配置Git时,加上--global参数是针对当前用户起作用的;不加--global参数是只针对当前仓库起作用。

每个仓库的Git配置文件都放在.git/config文件中:

[core]
    repositoryformatversion = 0
    filemode = false
    bare = false
    logallrefupdates = true
    symlinks = false
    ignorecase = true
    hideDotFiles = dotGitOnly
[remote "origin"]
    url = https://github.com//testGit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "dev"]
    remote = origin
    merge = refs/heads/dev
[alias]
    st = status

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

其中,别名就在[alias]后面,要删除别名,直接将对应的行删除即可。

而当前用户的Git配置文件 放在用户主目录(如Win10,‪C:\Users\Administrator\.gitconfig)下的一个隐藏文件.gitconfig中:

[user]
    name = user name
    email = Email
    eamil = Email
[github]
    user = username
[color]
    ui = true
[alias]
    st = status
    lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
    last = log -1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

当然,配置别名 也可直接修改配置文件完成。
2.7.3 搭建Git服务器

其实,远程仓库 除了24小时都可以提交各自的修改外,跟本地仓库并无其他区别。

场景:不想公开项目源代码,又不想给GitHub上付费,自己的命运自己掌握。

搭建属于自己的一台Git服务器作为私有仓库:
1、准备一个运行Linux的机器(推荐Ubuntu或Debian);
2、安装git:

$ sudo apt-get install git

    1

3、创建一个git用户,用于运行git服务:

$ sudo adduser git

    1

4、创建证书登录:
收集所有需要登录的用户的公钥(即 它们各自的id_rsa.pub文件),把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
5、初始化Git仓库:
先选定一个目录作为Git仓库,假设为/srv/sample.git,在/srv目录下输入命令:

$ sudo git init --bare sample.git

    1

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

$ sudo chown -R git:git sample.git

    1

6、禁用shell登录:
出于安全考虑,第3步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash

    1

改为:

git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

    1

这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。
7、clone远程仓库:
现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:

$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.

    1
    2
    3

管理公钥

若团队不大,将每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件是可行的。

如果团队上百人,可使用Gitosis进行管理公钥。

管理权限

为保护项目源码安全,知识版权很重要,需在版本控制系统中设置一套完善的权限控制,比如 每个人是否有读写权限,精确到某个分支,甚至某个目录下。

因为Git最初是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。

不过,因为Git支持钩子(hook),所以可在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite工具就为此而生。
3、免费的远程仓库
3.1 GitHub

一直使用GitHub作为免费的远程仓库,应用于开源项目,是最佳之选。同时,GitHub还是一个开源协作社区,鉴于Git强大的clone和分支功能,使得每个人都可以自由地参与各种开源项目。即我们可以参与其他人的开源项目、他人也可以参与我们的开源项目。

如何参与一个开源项目?以tensorflow为例,步骤:
1、在tensorflow项目主页,点击Fork按钮就在自己账号下clone tensorflow仓库;
2、将tensorflow从自己账号clone到本地,如此,就可以推送我的修改(如修复bug、新增功能);而如果从作者仓库URL clone,是不能推送修改的,因为没有权限;
3、如果希望tensorflow接受我的修改,可在GitHub发起一个Pull requests,等待对方接受即可。
3.2 码云

国内Git托管服务平台:码云,跟马云没关系!哈哈~

简直和GitHub一样。

参考:
Git官方网站
---------------------
作者:神是念着倒
来源:CSDN
原文:https://blog.csdn.net/weixin_38256474/article/details/82835603
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(git,git)