转载: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
(use "git checkout --
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
(use "git checkout --
modified: readme.txt
Untracked files:
(use "git add
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
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/
remote:
To https://github.com/
* [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]:
1
2
3
4
5
上述用的这种URL:[email protected]:
也可用:https://github.com/
在这里插入图片描述
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
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
(use "git checkout --
modified: readme.txt
Untracked files:
(use "git add
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
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
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/
origin https://github.com/
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/
1578051..69e6c1c master -> master
1
2
3
4
5
6
7
8
9
10
11
查看URL:
https://github.com/
场景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/
remote:
To https://github.com/
* [new branch] dev -> dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
查看URL:
https://github.com/
不过,并不是非得把本地分支往远程仓库上推送,一般性原则:
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/
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/
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/
! [rejected] dev -> dev (fetch first)
error: failed to push some refs to 'https://github.com/
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/
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
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/
* [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/
* [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/
- [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/
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
情况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/
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
版权声明:本文为博主原创文章,转载请附上博文链接!