走进GIT的世界(未完待续)

楔子

Git是什么?
Git是目前世界上最先进的分布式版本控制系统(没有之一)。

Git有什么特点?
简单来说就是:高端大气上档次!

那什么是版本控制系统?
VSS CVS GIT 都是,可自行搜索

集中式vs分布式
https://www.liaoxuefeng.com/wiki/896043488029600/896202780297248

为什么要进行版本控制?这个问题回答的角度就太多了
代码不能完全放在程序员本机的管理手段之一
备份的需求(回溯,找出历史版本的需求)
通过版本的发布高效的进行资料的投递(避免歧义等)
版本控制是质量控制的重要组成部分
等等。


第一章 “故事”也特么可以称之为“事故”

Linus在1991年创建了开源的Linux
Linux的壮大是靠全世界热心的志愿者参与
2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码
Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。
有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符(有没有觉得有点沙雕?

2002年,代码库之大让Linus很难继续通过手工方式管理了
社区的弟兄们也对这种方式表达了强烈不满
于是Linus选择了一个商业的版本控制系统BitKeeper
BitKeeper的东家BitMover公司出于人道主义精神授权Linux社区免费使用这个版本控制系统(人道主义?另一个沙雕来了

安定团结的大好局面在2005年就被打破了
原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。
开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个)
被BitMover公司发现了(沙雕年年有今年特别多)于是BitMover公司怒了,要收回Linux社区的免费使用权
Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!
一个月之内,Linux系统的源码已经由Git管理了!(静观一个沙雕牛逼的飞起来

2008年,GitHub网站上线了
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。


第二章 天上地下宇宙无极唯我独尊武学总纲

最有效的学习方法是讲给别人听(教授),再者是讨论(现在天天给我初一的儿子灌输这个费曼学习法)
而对我来说,最有效的学习方法有以下方面
从批判的角度来思考问题(多说几个不,带着问题进学习
环境如果已经存在,先接受结果,再考虑怎么改进他(也就是常问几个为什么
如果我自己要做一个GIT会是什么样子?我会怎么来做呢?等。
先来看看已经存在的这个东西它是个啥吧,这里先给出结论(时刻保持一颗对前人尊敬的心

因为Git跟踪并管理的是修改,而非文件。
因为Git跟踪并管理的是修改,而非文件。
因为Git跟踪并管理的是修改,而非文件。
(三遍,你懂的)

你会问,什么是修改?
比如你新增了一行,这就是一个修改,
删除了一行,也是一个修改,
更改了某些字符,也是一个修改,
删了一些又加了一些,也是一个修改,
甚至创建一个新文件,也算一个修改。

如果不是管理修改,而是管理文件将会是什么样?
新建文本文档
新建文本文档(1)
新建文本文档(2)
新建文本文档-2020-03-03
新建文本文档-2020-03-04-人事
同一个文档会在你的电脑磁盘存成不同需求的不知道多少个副本
电脑硬盘(或者公司服务器)要足够大,也许才能放的下
当人事问要一个文件的时候,你再手动的从这些文档中找出来发给他,其实我们希望能通过一个系统进行交付的。

先上手试试,找已有的 git 试试看它怎么管理修改的

手工建立一个文本文件 readme.txt,内容包含如下几行

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

连续使用几个git命令先看看它的效果($开头的为输入的命令,仔细看,其他的是一些控制台输出,参考看)

$ git add readme.txt

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

//修改readme.txt 文件,内容如下(做实验不用输入这个cat命令,下同)
$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.

$ git add readme.txt

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
      modified:   readme.txt

//这次add完没有立即commit,而是再次修改readme.txt 文件,内容如下
$ cat readme.txt 
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.

//第二次修改后,进行commit
$ git commit -m "git tracks changes"
[master 519219b] git tracks changes 1 file changed, 1 insertion(+)

$ 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:   readme.txt

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

咦,怎么第二次的修改没有被提交?
别激动,我们回顾一下操作过程:
第一次修改 -> git add -> 第二次修改 -> git commit

以上的控制台看起来太复杂?简单写就是做如下这么一个实验。
编辑生成readme.txt
git add
git commit
修改readme.txt(第一次修改)
git add
修改readme.txt (这第二次修改并没有被提交)
git commit


Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,
但是,在工作区的第二次修改并没有放入暂存区
所以,git commit只负责把暂存区的修改提交了
也就是第一次的修改被提交了
第二次的修改不会被提交。

可以理解成,如果修改需要立即提交到版本库,则 add 跟 commit应该成对的出现,这针对一个文件
对于多个文件,可以一次进行commit,例如

$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."

用这个例子来理解什么叫做“管理修改”,以及理解git的这些命令(命名)
反过来说
git add 这个命令其实并不是把文件加入到git的仓库
而是告诉git,
去对比一下仓库跟开发者手头手头的代码的差别
并且把这些差别记录到暂存区去,也就是git管理的修改
如果你每次修改之后,不敲击 git add 这个命令,其实git这个工具不会主动获得变化的。
对于 git commit 这个命令的参数 -m" changes....." 应该指的是 memo 

当你要进行变化确认入库时,最好还是带上一个说明吧,对本次操作说明一下。


第三章 天降神器之屠龙在手

linux下的安装

$ git
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

像上面的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。

Debian或Ubuntu Linux,sudo apt-get install git

老一点的Debian或Ubuntu Linux,要把命令改为sudo apt-get install git-core
因为以前有个软件也叫GIT(GNU Interactive Tools),结果Git就只能叫git-core了。
由于Git名气实在太大,后来就把GNU Interactive Tools改成gnuit,git-core正式改为git。

如果是其他Linux版本,可以直接通过源码安装。
先从Git官网下载源码,然后解压
依次输入:./config,make,sudo make install(需要有基本的编译环境)

WINDOWS下的的安装

git的下载(客户端) 

官方页面:https://git-scm.com/download/win
直接下载地址 https://github.com/git-for-windows/git/releases/download/v2.25.1.windows.1/Git-2.25.1-64-bit.exe

在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!

基础设置

$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"

创建版本库

// linux 下是这样的

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

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

// windows 下是这样

cd /d/work/raymotech                                                 // 键入命令
turui@turui-PC MINGW64 /d/work/raymotech                             // git bash 窗口显示

$ git init                                                           // 键入命令
Initialized empty Git repository in D:/work/raymotech/.git/          // git bash 窗口显示

turui@turui-PC MINGW64 /d/work/raymotech (master)                    // git bash 窗口显示


瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository)
细心的读者可以发现当前目录下多了一个.git的目录
这个目录是Git来跟踪管理版本库的
没事千万不要手动修改这个目录里面的文件
不然改乱了,就把Git仓库给破坏了
如果你没有看到.git目录,那是因为这个目录默认是隐藏的
用 ls -ah命令就可以看见

讲到这里,必须重点说明一下,GIT最开始的使用一定为单机(也就是个单机的游戏)
如果单机的GIT都没办使用好的话,就更不要谈联网使用,Github的使用了
本地的版本库有了,不管联网不联网,都可以尝试测试、使用git的版本管理(控制)功能
等常用命令都熟悉了,行为习惯也比较标准了,进阶将重点完成联网的使用(网络游戏)

Git能管理的文件类型

(原文中有些有歧义的说法我就没有摘录了)
版本控制系统可以告诉你每次的改动
比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。
而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化
只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB
但到底改了啥,版本控制系统不知道,也没法知道。
不幸的是,Microsoft的Word格式是二进制格式,
因此,版本控制系统是没法跟踪Word文件的改动的,
如果要真正使用版本控制系统,就要以纯文本方式编写文件。
我认为,这里应该描述为
文本类型的文件,在版本控制系统的管理下,可以得到更多的管理细节
其他类型的文件,由于只能对比出二进制文件的大小等变化,所以管理细节比较粗糙

windows下文件(代码)编辑的注意事项

因为文本是有编码的
比如中文有常用的GBK编码
日文有Shift_JIS编码
如果没有历史遗留问题,强烈建议使用标准的UTF-8编码
所有语言使用同一种编码,既没有冲突,又被所有平台所支持。
千万不要使用Windows自带的记事本编辑任何文本文件
Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件
他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符
你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”
明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的
建议你下载Notepad++代替记事本,不但功能强大,而且免费!
记得把Notepad++的默认编码设置为UTF-8 without BOM即可
set-utf8-notepad++

注:
这些都准备好之后,同学们,小朋友们就可以在本机愉快的玩耍了
下一章就让我们一起来熟悉git命令吧
通过命令的使用看能解决哪些问题
通过命令的使用看能达到什么样的效果


第四章 无上秘籍之九阴九阳

官方文档

 https://git-scm.com/docs

帮助

$ git --help
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone             Clone a repository into a new directory
   init              Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add               Add file contents to the index
   mv                Move or rename a file, a directory, or a symlink
   restore           Restore working tree files
   rm                Remove files from the working tree and from the index
   sparse-checkout   Initialize and modify the sparse-checkout

examine the history and state (see also: git help revisions)
   bisect            Use binary search to find the commit that introduced a bug
   diff              Show changes between commits, commit and working tree, etc
   grep              Print lines matching a pattern
   log               Show commit logs
   show              Show various types of objects
   status            Show the working tree status

grow, mark and tweak your common history
   branch            List, create, or delete branches
   commit            Record changes to the repository
   merge             Join two or more development histories together
   rebase            Reapply commits on top of another base tip
   reset             Reset current HEAD to the specified state
   switch            Switch branches
   tag               Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch             Download objects and refs from another repository
   pull              Fetch from and integrate with another repository or a local branch
   push              Update remote refs along with associated objects

'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.

设置全局信息

// 设置全局信息
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"

创建版本仓库

// 创建版本仓库,一般是空的时候才这样用
$ git init

查看仓库状态

// 查看仓库当前的状态
$ git status

提交修改

// 告诉git去看下某个文件的变化
// 并将变化归并(执行)到某个仓库中
// 默认是归并到master仓库(repository)中
// 两个一般成对使用
// 多个文件可以同时执行一个commit
$ git add readme.txt
$ git commit -m "wrote a readme file"

对比修改

// 上一次是如何修改的,显示的格式正是Unix通用的diff格式
$ git diff readme.txt 

关于日志

// 显示从最近到最远的提交日志
// 可以看到3次提交
// 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:
// 1094adb7b9b3807259d8cb349e7df1d4d6477073 这个叫commit id
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:06:15 2018 +0800

    append GPL

$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL

关于版本回退

// 回退版本
// 上一个版本就是HEAD^
// 上上一个版本就是HEAD^^
// 当然往上100个版本写100个^比较容易数不过来
// 所以写成HEAD~100。
$ git reset --hard HEAD^
HEAD is now at e475afc add distributed
// 回退到任意版本
// 版本号没必要写全,前几位就可以了
// Git会自动去找。当然也不能只写前一两位
// 因为Git可能会找到多个版本号,就无法确定是哪一个了。
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL

HEAD指向的版本就是当前版本
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针
当你回退版本的时候,Git仅仅是把HEAD从指向append GPL

查看操作历史

// 查看操作历史
$ git reflog
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file

Git允许我们在版本的历史之间穿梭
使用命令git reset --hard commit_id
穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

关于 --hard 参数,这个讲起来有点复杂,可以参考这里(回头专门补充一下)
https://www.cnblogs.com/keystone/p/10700617.html
reset这个操作还是要慎用!!!

文件找回

// git checkout -- file可以丢弃工作区的修改
// readme.txt自修改后,未放到暂存区,回到版本库的状态;
// readme.txt自修改后,已放到暂存区,回到暂存区的状态;
// git checkout -- file命令中--很重要,没有--,就变成了“切换到另一个分支”的命令
$ git checkout -- readme.txt

// git checkout -- file 会和 git reset HEAD file 组合使用
// 先回退文件在暂存库的版本,再进行文件恢复
$ git reset HEAD readme.txt
$ git checkout -- readme.txt

文件删除

// 删除一个文件
// rm 删除本地 git rm 提交删除命令 git commit 成对使用
$ rm test.txt
$ git rm test.txt
rm 'test.txt'

$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

// 本地文件如果删没了,可以用 git check out 命令重新取回来
$ git checkout -- test.txt

远程仓库

// 本地仓库跟远程仓库关联、解除关联相关操作
// 习惯上给远程仓库起名为 origin 

// 列出已经存在的远程分支
$ git remote 

// 列出详细信息,在每一个名字后面列出其远程url
// 此时, -v 选项显示对应的克隆地址。
$ git remote -v | --verbose

// 添加一个远程仓库 
// git remote add <远程仓库名> <远程仓库url>
$ git remote add origin [email protected]:xxxxxx/xxxxxx.git

// 删除一个远程仓库跟本地的关联
// git remote remove repositiry_name

// 将本地的master仓库push到远程origin这个仓库
$ git push -u origin master

数据推送(上传)到远程

// git push的一般形式为 git push <远程主机名> <本地分支名>  <远程分支名>
$ git push origin master:refs/for/master

// 不带任何参数的git push,默认只推送当前分支,这叫做simple方式
// 还有一种matching方式,会推送所有有对应的远程分支的本地分支
// Git 2.0之前默认使用matching,现在改为simple方式
// 如果想更改设置,可以使用git config命令。
// git config --global push.default matching 
// OR git config --global push.default simple
// 可以使用git config -l 查看配置


// 注意看下面的变形使用

// 如果远程分支被省略
// 则表示将本地分支推送到与之存在追踪关系的远程分支(通常两者同名)
// 如果该远程分支不存在,则会被新建
$ git push origin master

// 如果省略本地分支名
// 则表示删除指定的远程分支
// 因为这等同于推送一个空的本地分支到远程分支
// 等同于 git push origin --delete master
$ git push origin :refs/for/master 

// 如果当前分支与远程分支存在追踪关系
// 则本地分支和远程分支都可以省略
// 将当前分支推送到origin主机的对应分支
$ git push origin

// 如果当前分支只有一个远程分支,那么主机名都可以省略
// 形如 git push
// 可以使用git branch -r 查看远程的分支名
$ git push

// 如果当前分支与多个主机存在追踪关系
// 则可以使用 -u 参数指定一个默认主机
// 这样后面就可以不加任何参数使用git push
$ git push -u origin master
$ git push


// 不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机
$ git push --all origin 


// git push的时候需要本地先git pull更新到跟服务器版本一致
// 如果本地版本库比远程服务器上的低,那么一般会提示你git pull更新
// 如果一定要提交,那么可以使用这个命令。
$ git push --force origin 

// git push 的时候不会推送分支,如果一定要推送标签的话那么可以使用这个命令
$ git push origin --tags

克隆(远程)数据到本地

// 关于git clone

// 在使用git来进行版本控制时,为了得一个项目的拷贝(copy)
// 我们需要知道这个项目仓库的地址(Git URL)
// Git能在许多协议下使用,所以Git URL可能以ssh://, http(s)://, git://
// 或是只是以一个用户名(git 会认为这是一个ssh 地址)为前辍. 

// 有些仓库可以通过不只一种协议来访问
// 例如,Git本身的源代码你既可以用 git:// 协议来访问:
$ git clone git://git.kernel.org/pub/scm/git/git.git

// 也可以通过http 协议来访问:
$ git clone http://www.kernel.org/pub/scm/git/git.git

// git://协议较为快速和有效
// 但是有时必须使用http协议,比如你公司的防火墙阻止了你的非http访问请求.
// 如果你执行了上面两行命令中的任意一个,你会看到一个新目录: 'git'
// 它包含有所的Git源代码和历史记录.

// 在默认情况下,Git会把"Git URL"里最后一级目录名的'.git'的后辍去掉
// 做为新克隆(clone)项目的目录名: 
// 例如. git clone http://git.kernel.org/linux/kernel/git/torvalds/linux-2.6.git
// 会建立一个目录叫'linux-2.6'

// 另外,如果访问一个Git URL需要用法名和密码
// 可以在Git URL前加上用户名,并在它们之间加上@符合以表示分割,
// 然后执行git clone命令,git会提示你输入密码。
$ git clone robin.hu@http://www.kernel.org/pub/scm/git/git.git
// 这样将以作为robin.hu用户名访问http://www.kernel.org/pub/scm/git/git.git
// 然后按回车键执行git clone命令,git会提示你输入密码。

// 另外,我们可以通过-b <name>来指定要克隆的分支名,比如
$ git clone -b master2 ../server .
// 表示克隆名为master2的这个分支,如果省略-b <name>表示克隆master分支。

// 只克隆一个分支 携带这个参数 --single-branch
$ git clone -b mvp-dev-more --single-branch [email protected]:tancolo/MOOC.git

// 只想clone 某个git仓库最近xx次提交的代码
// --depth=commit_num 或者 --depth commit_num
git clone --depth=10 https://github.com/tancolo/MOOC.git

关于分支

每次提交Git都把它们串成一条时间线,这条时间线就是一个分支。(上一幅图辅助理解下)
只有一条时间线,在Git里,这个分支叫主分支,即master分支
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
HEAD指向当前工作的分支(只有一个分支的时候 ,它当然指向master了)

git-br-initial
创建新的分支HEAD会指向新的分支(如图)

git-br-create

新的分支再次做提交(commit)的时候,
HEAD会持续指向新的分支,也就是说HEAD这时候始终会指向当前工作的分支(如下图)

git-br-dev-fd

当在dev分支进行合并操作时,实际上是在告诉git,把master(默认)分支弄的跟我一样来
并且HEAD指向当前工作点(因为已经合并了master跟dev是一个点)
 

git-br-ff-merge

如图所示命令如下

// 首先,我们创建dev分支,然后切换到dev分支:
$ git checkout -b dev
Switched to a new branch 'dev'

// git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'

// 然后,用git branch命令查看当前分支:
// git branch命令会列出所有分支,当前分支前面会标一个*号。
$ git branch
* dev
  master

// 然后,我们就可以在dev分支上正常提交
// 修改一下readme.txt,随便添加一些内容,然后提交:
$ git add readme.txt 
$ git commit -m "branch test"
[dev b17d20e] branch test 1 file changed, 1 insertion(+)


// 现在,dev分支的工作完成,我们就可以切换回master分支:
$ git checkout master
Switched to branch 'master'

做完上述命令,git版本库的情况是这样的

git-br-on-master

所以这时候,你查看readme.txt文件,发现刚才添加的内容不见了!

// 现在,我们把dev分支的工作成果合并到master分支上
$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
 readme.txt | 1 + 1 file changed, 1 insertion(+)

合并完成后,GIT仓库的状态变为图4的情况
再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”
也就是直接把master指向dev的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。
合并完成后,就可以放心地删除dev分支了:

$ git branch -d dev
Deleted branch dev (was b17d20e).

删除后,查看branch,就只剩下master分支了:

$ git branch
* master

我们注意到切换分支使用git checkout <branch>,和前面面讲过的文件取回 git checkout -- <file> 同一个命令,有两种作用,确实有点令人迷惑。
切换分支这个动作,用switch更科学。因此,最新版本的Git提供了新的git switch命令来切换分支

// 创建并切换到新的dev分支,可以使用:
$ git switch -c dev

// 直接切换到已有的master分支,可以使用:
$ git switch master

// 删除分支:
$ git branch -d <name>

Git鼓励大量使用分支

分支合并中的冲突,我们构造一种场景

git-br-feature1
什么?上面这个场景不知道怎么做?其实很容,命令如下

$ git switch -c feature1
Switched to a new branch 'feature1'

// 手工修改readme.txt

$ git add readme.txt
$ git commit -m "AND simple"
[feature1 14096d0] AND simple 1 file changed, 1 insertion(+), 1 deletion(-)

$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.  (use "git push" to publish your local commits)

// 手工修改readme.txt
$ git add readme.txt 
$ git commit -m "& simple"
[master 5dc6824] & simple 1 file changed, 1 insertion(+), 1 deletion(-)

从上面的图形大家可以看出来,master分支和feature1分支各自都分别有新的提交
很明显,这时候如果要做合并的话,冲突即将产生了
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,
但这种合并就可能会有冲突,我们试试看

$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。
手工(人为)解决掉这些冲突后,再进行合并吧。
使用merge命令的时候,推荐加上参数 --no-ff(也就是默认什么参数都不带的Fast-forward模式并不推荐的,所以别偷懒哦

创建并切换dev分支
修改readme.txt,并add,commit
切回master
合并

git merge --no-ff -m “merge with no-ff” dev
 
--no-ff模式, 普通合并,有历史,看得出做过合并
fast forward模式,快速合并,看不出做过合并
通常,合并分支时,
Git尽可能用 fast forward 模式,
但这种模式,删除分支后,会丢掉分支信息。

实际开发中的分支管理策略

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。


第五章 抽丝剥茧之一窥究竟

前面反复提到几个名词“工作区”、“暂存区”、“版本库(又称为仓库)”
看起来大概是这样的

git-repo

工作区(Working Directory)就是你在电脑里能看到的目录
版本库(Repository)工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区
还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

对于这3个区域常见的操作有

git add把文件从工作区>>>>暂存区

git commit把文件从暂存区>>>>仓库

git diff查看工作区和暂存区差异

git diff --cached查看暂存区和仓库差异

git diff HEAD 查看工作区和仓库的差异

git checkout 放弃对工作区中某文件的修改
将工作区中该文件的状态恢复到该文件上次提交到暂存区时的状态。

add 会修改暂存区的内容
commit 会修改暂存区和仓库的内容
checkout 会修改工作区的内容
reset 会修改工作区的内容


第六章 功力大成之渡劫飞升

github

gitee


第七章 返璞归真之自成一界

本地服务器搭建
nas的使用

发布了36 篇原创文章 · 获赞 33 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/turui/article/details/104626612