image-20201118224039346

img

git init

git add

git commit -m “asdasd”

git status

git diff

git diff HEAD -- readme.txt命令可以查看工作区和版本库里面最新版本的区别:

git log

看到的一大串类似1094adb...的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

git log --pretty=oneline

Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb...(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

简而言之,执行 git reset HEAD 以取消之前 git add 添加

1
git reset --hard HEAD^

git log再看看现在版本库的状态:

最新的那个版本append GPL已经看不到了!好比你从21世纪坐时光穿梭机来到了19世纪,想再回去已经回不去了,肿么办?

办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个append GPLcommit id1094adb...,于是就可以指定回到未来的某个版本:

1
$ git reset --hard 1094a

或者

1
查看日志 `cat  .git/logs/refs/heads/master`,`cat  .git/logs/HEAD`

image-20201120104147958

你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?

在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到add distributed版本时,再想恢复到append GPL,就必须找到append GPL的commit id。Git提供了一个命令

1
git reflog

用来记录你的每一次命令:

简而言之,执行 git reset HEAD 以取消之前 git add 添加

git reset

1
2
3
4
5
6
7
8
9
$ git reset HEAD^            # 回退所有内容到上一个版本  
$ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本
$ git reset 052e # 回退到指定版本
实例:
$ git reset --soft HEAD~3 # 回退上上上一个版本

--hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:

git reset --hard HEAD

–mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变**。谨慎使用 –hard 参数,它会删除回退点之前的所有信息。**

1
2
git restore --stage readme.txt #丢弃当前暂存区的改动  但是不改变工作区
git restore readme.txt # 丢弃当前工作区的改动,让这个文件和所在的HEAD仓库内容一样 类似于 git reset --hard参数

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

git-br-initial

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

git-br-create

你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

git-br-dev-fd

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

git-br-ff-merge

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

git-br-rm

https://www.open-open.com/lib/view/open1328069889514.html

日志

1
git log --graph --pretty=oneline --abbrev-commit

执行 git fetch origin master 时,它的意思是从名为 origin 的远程上拉取名为 master 的分支到本地分支 origin/master 中。既然是拉取代码,当然需要同时指定远程名与分支名,所以分开写。

执行 git merge origin/master 时,它的意思是合并名为 origin/master 的分支到当前所在分支。既然是分支的合并,当然就与远程名没有直接的关系,所以没有出现远程名。需要指定的是被合并的分支。

执行 git push origin master 时,它的意思是推送本地的 master 分支到远程 origin,涉及到远程以及分支,当然也得分开写了。

还可以一次性拉取多个分支的代码:git fetch origin master stable oldstable

也还可以一次性合并多个分支的代码:git merge origin/master hotfix-2275

得到某个文件修改历史 git log xxxdev

master

img

img

Git新命令switch和restore

工作区某文件恢复到指定版本的时候: git restore -s [hash] xxxx.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:02:19] 
$ cat readme.txt
git is version ontrol system
add new line
add two
add 3rd
git is free softwoare

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:02:21]
$ git status
位于分支 master
无文件要提交,干净的工作区

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:02:23]
$ cat test1
111

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:02:29]
$ git restore f8ef5a0 readme.txt
error: 路径规格 'f8ef5a0' 未匹配任何 git 已知文件

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:02:43] C:1
$ git restore -help
用法:git restore [<选项>] [--source=<分支>] <文件>...

-s, --source <tree-ish>
要检出哪一个树
-S, --staged 恢复索引
-W, --worktree 恢复工作区(默认)
--ignore-unmerged 忽略未合并条目
--overlay 使用叠加模式
-q, --quiet 不显示进度报告
--recurse-submodules[=<checkout>]
control recursive updating of submodules
--progress 强制显示进度报告
-m, --merge 和新的分支执行三方合并
--conflict <风格> 冲突输出风格(merge 或 diff3)
-2, --ours 对尚未合并的文件检出我们的版本
-3, --theirs 对尚未合并的文件检出他们的版本
-p, --patch 交互式挑选数据块
--ignore-skip-worktree-bits
对路径不做稀疏检出的限制
--pathspec-from-file <文件>
从文件读取路径表达式
--pathspec-file-nul 使用 --pathspec-from-file,路径表达式用空字符分隔


# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [12:03:20] C:129
$ git restore -s f8ef5a0 readme.txt

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [12:04:14]
$ cat readme.txt
git is version ontrol system
git is free softwoare

工作区某文件恢复到暂存区的版本 git restore xxx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:49:11] 
$ cat readme.txt
git is version ontrol system
add new line
add two
add 3rd
git is free softwoare

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:49:19]
$ git status
位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: .readme.txt.un~

未跟踪的文件:
(使用 "git add <文件>..." 以包含要提交的内容)
test1

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:49:24]
$ echo "stup " >> readme.txt

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:51:54]
$ git status
位于分支 master
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: .readme.txt.un~
修改: readme.txt

未跟踪的文件:
(使用 "git add <文件>..." 以包含要提交的内容)
test1

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"



# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:52:28]
$ git add readme.txt

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:52:33]
$ git status
位于分支 master
要提交的变更:
(使用 "git restore --staged <文件>..." 以取消暂存)
修改: readme.txt

尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: .readme.txt.un~

未跟踪的文件:
(使用 "git add <文件>..." 以包含要提交的内容)
test1


# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:52:35]
$ echo "stupi" >> readme.txt

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:52:44]
$ cat readme.txt
git is version ontrol system
add new line
add two
add 3rd
git is free softwoare
stup
stupi

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:52:54]
$ git restore readme.txt

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master x [11:53:02]
$ cat readme.txt
git is version ontrol system
add new line
add two
add 3rd
git is free softwoare
stup

取消暂存区的内容,不影响工作区

1
git restore --staged <文件>

git reset

https://www.jianshu.com/p/cbd5cd504f14

git reset --soft

将HEAD引用指向给定提交。索引(暂存区)和工作目录的内容是不变的,在三个命令中对现有版本库状态改动最小。

git reset --mixed(git reset默认的模式)

HEAD引用指向给定提交,并且索引(暂存区)内容也跟着改变,工作目录内容不变。这个命令会将索引(暂存区)变成你刚刚暂存该提交全部变化时的状态,会显示工作目录中有什么修改。

git reset --hard

HEAD引用指向给定提交,索引(暂存区)内容和工作目录内容都会变给定提交时的状态。也就是在给定提交后所修改的内容都会丢失(新文件会被删除,不在工作目录中的文件恢复,未清除回收站的前提)。

img

新建分支 , 切换分支,创建跟踪分支

由于git中分支仅仅是一个commit id的别名,所以checkout也可以切换到一个commit id

1
2
3
$ git checkout aaa # 切换到 aaa分支 
$ git checkout -b aaa # 创建aaa,然后切换到 aaa分支
$ git checkout commitid # 切换到某个commit id

新的switch命令用来接替checkout的功能,但switch不能切换到commit id

1
2
$ git switch aaa # 切换到 aaa分支 
$ git switch -c aaa # 创建aaa,然后切换到 aaa分支

命令查看当前分支

1
2
3
git branch -a #所有分支
-r 远程分支
-v

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>或者git switch <name>

创建+切换分支:git checkout -b <name>或者git switch -c <name>

1
2
git checkout -b totallyNotMaster o/master #tot分支跟踪 远程master
git switch -c xxx xxx

另一种设置远程追踪分支的方法就是使用:git branch -u 命令,执行:

1
git branch -u o/master foo

这样 foo 就会跟踪 o/master 了。如果当前就在 foo 分支上, 还可以省略 foo:

1
git branch -u o/master

合并某分支到当前分支:git merge <name>

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

git cherry-pick 当前记录后面跟自定义提交

  • git cherry-pick <提交号>...

如果你想将一些提交复制到当前所在的位置(HEAD

image-20201123104953047

1
2
3
4
git checkout master;
git cherry-pick C2;
git commit --amend;
git cherry-pick C3

git rebase 选分支挂在到指定分支后 -i重新排列

变基

1
2
3
4
5
6
git rebase [前驱分支] [要成为后继分支的分支]

git rebase caption bugfix # 把bugfix分支挂在caption后

git rebase [前驱分支] # 把当前分支挂在到后继分支 当前分支变基

还可以用来 fast-foward

image-20201123195919610

image-20201123105244807

1
2
3
$ git checkout mywork
$ git rebase origin
Shell

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

img

当’mywork‘分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除.

img

命令的形式为:

1
git rebase   [startpoint]   [endpoint]  --onto  [branchName]

其中,[startpoint] [endpoint]仍然和上一个命令一样指定了一个编辑区间(前开后闭),--onto的意思是要将该指定的提交复制到哪个分支上。
所以,在找到C(90bc0045b)和E(5de0da9f2)的提交id后,我们运行以下命令:

1
git  rebase   90bc0045b^   5de0da9f2   --onto master

注:因为[startpoint] [endpoint]指定的是一个前开后闭的区间,为了让这个区间包含C提交,我们将区间起始点向后退了一步。

git commit --amend 修改记录,但是不增加一个commit,

移动某个分支名到某个hash

git branch -f [分支名] [hash]

选择父提交记录

操作符 ^~ 符一样,后面也可以跟一个数字。

但是该操作符后面的数字与 ~ 后面的不同,并不是用来指定向上返回几代,而是指定合并提交记录的某个父提交。还记得前面提到过的一个合并提交有两个父提交吧,所以遇到这样的节点时该选择哪条路径就不是很清晰了。

Git 默认选择合并提交的“第一个”父提交,在操作符 ^ 后跟一个数字可以改变这一默认行为。

image-20201123161505541

image-20201123161517116

image-20201123161551402

image-20201123165208782

获取远程仓库 某个分支 3种方法

1
2
从远程分支 checkout 出来的本地分支,称为_跟踪分支(tracking branch)_。跟踪分支是一种和远程分支有直接联系的本地分支。在跟踪分支里输入git push,Git 会自行推断应该向哪个服务器的哪个分支推送数据。反过来,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。
在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master

https://blog.csdn.net/weixin_41287260/article/details/98987135

常用的克隆命令应该是这个: git clone <url>;这个命令其实是下面命令的简写形式:git clone -b master <url>

1. 对于比较少分支的仓库–方法1

思路:先查看远程分支,然后在本地创建和远程仓库同名的分支。

关键命令git branch dev origin/devgit switch -c dev origin/dev,即新建一个本地分支来跟踪远程的某一分支,创建该分支后,远程分支内容已拉取到本地分支。(或者你可以直接用git checkout -b dev origin/dev,创建分支,并切换到该分支)

2. 对于比较少分支的仓库–方法2

git clone -b readme url:下载该仓库的readme分支的内容。

3. 对于比较多分支的仓库

1
for b in `git branch -r | grep -v -- '->'`; do git branch --track ${b##origin/} $b; done

删除远程分支

1
如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放稳定代码的地方),可以用这个非常无厘头的语法来删除它:git push [远程名] :[分支名]。如果想在服务器上删除serverfix 分支,运行下面的命令:
1
2
$ git push origin :serverfix 
To git@github.com:schacon/simplegit.git - [deleted] serverfix
1
咚!服务器上的分支没了。你最好特别留心这一页,因为你一定会用到那个命令,而且你很可能会忘掉它的语法。有种方便记忆这条命令的方法:记住我们不久前见过的 git push [远程名] [本地分支]:[远程分支] 语法,如果省略 [本地分支],那就等于是在说“在这里提取空白然后把它变成[远程分支]”。

添加远程库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,命令格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
git remote add [shortname] [url]
# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [17:16:29]
$ git remote add origin git@github.com:991688344/Manjaro.git

# rick @ rick-win-manjaro in ~/TMP/GIT-Learn on git:master o [17:17:52]
$ git remote -v
origin git@github.com:991688344/Manjaro.git (fetch)
origin git@github.com:991688344/Manjaro.git (push)


执行时加上 -v 参数,你还可以看到每个别名的实际链接地址。
$ git remote -v
origin git@github.com:tianqixin/runoob-git-test.git (fetch)
origin git@github.com:tianqixin/runoob-git-test.git (push)

显示某个远程仓库的信息

1
2
3
4
5
$ git remote show git@github.com:991688344/Manjaro.git
* 远程 git@github.com:991688344/Manjaro.git
获取地址:git@github.com:991688344/Manjaro.git
推送地址:git@github.com:991688344/Manjaro.git
HEAD 分支:main

git clone git fetch

image-20201123174313980

git fetch 的参数和 git push 极其相似。他们的概念是相同的,只是方向相反罢了(因为现在你是下载,而非上传)

image-20201123175459916

image-20201123175732711

image-20201123175803046

image-20201123204405623

image-20201123204445599

image-20201123204504399

推送到远程仓库 git push

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git push -u origin master                           
枚举对象中: 16, 完成.
对象计数中: 100% (16/16), 完成.
使用 4 个线程进行压缩
压缩对象中: 100% (15/15), 完成.
写入对象中: 100% (16/16), 1.62 KiB | 331.00 KiB/s, 完成.
总共 16(差异 3),复用 0(差异 0),包复用 0
remote: Resolving deltas: 100% (3/3), done.
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/991688344/Manjaro/pull/new/master
remote:
To github.com:991688344/Manjaro.git
* [new branch] master -> master
分支 'master' 设置为跟踪来自 'origin' 的远程分支 'master'

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

image-20201123201821420

image-20201123202927666

image-20201123203002356

image-20201123203016033

要同时为源和目的地指定 <place> 的话,只需要用冒号 : 将二者连起来就可以了:

1
git push origin <source>:<destination>

image-20201123203509240

image-20201123203532626

获取远程仓库 git pull = git fetch + git merge

git pull命令的作用是:取回远程主机某个分支的更新,再与本地的指定分支合并,

将远程存储库中的更改合并到当前分支中。在默认模式下,git pullgit fetch后跟git merge FETCH_HEAD的缩写。

git pull origin foo 相当于:

1
git fetch origin foo; git merge o/foo

还有…

git pull origin bar~1:bugFix 相当于:

1
git fetch origin bar~1:bugFix; git merge bugFix

image-20201123205506695

image-20201123205544298

image-20201123205754828

简单的多人协作流程

最简单的协作方式之一:先在自己的特性分支中工作一段时间,完成后合并到自己的 master 分支;然后下载合并 origin/master 上的更新(如果有的话),再推回远程服务器。一般的协作流程如图所示:

多用户共享仓库协作方式的一般工作流程时序

1. 其他人在我之前修改过远程仓库,本地代码版本落后

git pull 就是 fetch 和 merge 的简写,类似的 git pull --rebase 就是 fetch 和 rebase 的简写!

rebase

image-20201123182036464

单条命令: git pull --rebase

image-20201123182053222

merge

image-20201123182145994

单条: git pull

2. master被锁,需要pull request

tag起锚点作用 , describe寻找最近锚点

image-20201123155518893

git describe 的语法是:

1
git describe <ref>

<ref> 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会以你目前所检出的位置(HEAD)。

它输出的结果是这样的:

1
<tag>_<numCommits>_g<hash>

tag 表示的是离 ref 最近的标签, numCommits 是表示这个 reftag 相差有多少个提交记录, hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。

ref 提交记录上有某个标签时,则只输出标签名称

最近锚点

HEAD指针分离状态

https://blog.csdn.net/start_mao/article/details/94722393