学习笔记|Git

本文最后更新于:5 years ago

很久以前在公众号上开了一个坑,三分钟一起窥探Git门缝(上),迟迟没有写下,最近刚好有时间系统的过一遍 git,熟悉熟悉其各类应用场景,算是填坑完毕⛳️。

1.user信息管理

1
2
3
4
5
6
7
8
9
10
11
12
###配置user信息
git config --global user.name 'your_name'
git config --global user.email 'your_email@domain.com'

--global :全球
--local :本地,单个项目中使用

###显示user信息
git config --list --global

###编辑配置文件
git config --global --edit

2.暂存区管理

1
2
3
4
5
6
7
8
9
git add readme.md        #添加到暂存区
git add -u #将更改过的、已经在git中管理的文件,全都添加到暂存区

--------------------------------------------
git reset HEAD #将暂存区恢复成和HEAD一致(即清空暂存区),不改变工作区
git reset HEAD -- 1.txt 2.txt #取消暂存区部分文件的更改,不改变工作区

--------------------------------------------
git checkout -- 2.txt #将工作区文件恢复和暂存区一致

英文:

1
2
3
4
5
use "git reset HEAD <file>..." to unstage
#unstage:不发生 stage:使发生

(use "git checkout -- <file>..." to discard changes in working directory)
#discard:丢弃、放弃 directory:目录

3.版本库管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
git status        #查看状态

--------------------------------------------
git commit -m'版本信息' #提交到git中
git commit -am'版本信息' #对于修改的工作区的文件直接提交到版本库里

--------------------------------------------
git reset --hard aaaa6666 #撤销版本库,撤销暂存区,撤销工作区,更改到aaaa6666版本
git reset --hard HEAD #将暂存区和工作区恢复和HEAD一致

--------------------------------------------
git mv file_name new_file_name #更改文件名
git rm file_name #删除版本库中文件
###更改完需要commit一次

4.commit 管理

(1)更改最近一次提交的版本信息

1
git commit --amend    

(2)更改老旧 commit 的 message

  • 更改 message,必将更改此次 commithash 值;更改此次 commithash 值,就要基于其父亲 commit 来改变,这叫 rebase

  • 根据下方的提示,将 pick 改成 r

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
git rebase -i aaaa6666         # aaaa6666为所修改commit的 父亲commit 的hash值

###得到以下交互信息:
pick 17eeb4a change index ###将要修改的massage,pick改为r
pick 3c052e5 move readme.md to readmine + Add readme ###不需修改的massage,保持 pick
pick 0abe5ee rm rqeq1 ###不需修改的massage,保持 pick
# Rebase e7d6113..0abe5ee onto aaaa6666 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.

随后跳出的页面就是修改 massage。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
change index   ### 修改成自己想要的 massage

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: ...
#
# interactive rebase in progress; onto aaaa6666
# Last commands done (1 commands done):
# reword e7d6113 ...
# Next command to do (0 remaining command):
# You are currently editing a commit while rebasing branch 'master' on 'aaaa6666'.
#
# Changes to be committed:
# modified: ...

(3)多个连续的commit合并成一个

meld:合并;previous:以前的

根据下方的提示,将 pick 改成 s

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
git rebase    -i aaaa6666 		#aaaa6666为合并的四个commit的 父亲commit 的hash值

###1.要合并前三条commit
pick d93a5a2 Add images+index #----必须保留一条pick
s e7d6113 add inin #----pick改为s
s 17eeb4a change index #----pick改为s
pick 3c052e5 move readme.md to readmine + Add readme
pick 634bfa3 rm rqeq1+2
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# You are editing the todo file of an ongoing interactive rebase.
-- INSERT --



###2.添加合并的massage
# This is a combination of 3 commits. #----在此处添加massage
# This is the 1st commit message:

Add images+index

# This is the commit message #2:

add inin

# This is the commit message #3:

change index

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sat Mar 7 20:32:23 2020 +0800
#
# interactive rebase in progress; onto cef862a
# Last commands done (3 commands done):
# squash e7d6113 add inin
# squash 17eeb4a change index
# Next commands to do (2 remaining commands):
# pick 3c052e5 move readme.md to readmine + Add readme
# pick 634bfa3 rm rqeq1+2
# You are currently rebasing branch 'master' on 'cef862a'.
#
-- INSERT --

(4)多个间隔的commit合并成一个

  1. 找到最老旧的 commitparents
  2. 手动在最上面添加 pick parents_hash
  3. 将要合并的 commit 剪切到 pick parents_hash 下面,并将 pick 改成 s
  4. 更改 massage

7.查看log

1
2
3
4
5
6
7
8
9
git log --oneline  #简介的查看log(当前分支)
git log --oneline -n2 #简介的查看log,最近的2条log(当前分支)

git log --all #查看所有分支的log日志
git log --all --graph -n50 #图形化查看分支父子关系,-n50 表示显示前 50 条 commit

gitk --all -n50 #图形化显示前 50 条commit

git log --pretty=format:"%h - %ae : %s" | grep google.com # 按 邮箱/团队/公司 过滤 log

8.分支管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
git branch -v  #查看本地有多少分支
git branch -a #显示本地和远端的分支

--------------------------------------------
git checkout master #切换分支
git checkout -b tmp2 413c5d9b76 #基于413c5d9b76创建新的分支tmp2
git checkout -b tmp2 tmp #基于分支tmp创建新分支tmp2
git checkout 413c5d9b76 #分离头指针(detached HEAD),基于413c5d9b76创建一个没有分支的工作区

--------------------------------------------
git branch -d branch_name #删除分支
git push origin --delete branch_name // 本地删除分支后,同步到远端仓库

--------------------------------------------
git merge dev #在master 分支上执行,将dev分支合并到master中

--------------------------------------------
git cherry-pick <commitHash> #将指定的提交应用于其他分支

9.比较版本差异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
git diff a0a5992 35f7cdf        #比较两个commit之间的差异

--------------------------------------------
git diff HEAD HEAD^1 #比较当前分支的commit 和 父亲的commit 之间的差异
git diff HEAD HEAD^
git diff HEAD HEAD~1

--------------------------------------------
git diff HEAD HEAD^^ ##比较当前分支的commit 和 父亲的父亲的commit 之间的差异
git diff HEAD HEAD~2

--------------------------------------------
git diff --cached #比较当前版本库 和 暂存区的差异
git diff #比较工作区 和 暂存区的差异
git diff -- file_name #比较工作区和暂存区中,关于file_name的差异 # 注意:file_name 与 -- 之前有空格

--------------------------------------------
git diff tmp master #比较两个分支的差异
git diff tmp master -- index.html #比较两个分支中index.html的差异

--------------------------------------------
git show hash # 查看某个hash 对应的更改,加上 -- filename 即可,只查看在 filename 文件中的更改

看懂 diff 信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
diff --git a/f1 b/f1      # 对比 a 版本的 f1 和 b 版本的 f1
index 6f8a38c..449b072 100644 # a 版本的 f1 和 b 版本的 f1 各自的哈希值
--- a/f1 # --- 表示改动前的版本
+++ b/f1 # +++ 表示改动后的版本,并不一定是改动后的文件增加了代码。
@@ -1,7 +1,7 @@ # -1,7 表示改动前的文件,从第 1 行开始 7 行发生了改动/产生了影响;
# +1,7 表示改动后的文件,从第 1 行开始 7 行发生了改动/产生了影响;
a
a
a
-a
+b
a
a
a

10.git文件夹内容

1
2
3
4
cat HEAD    #当前所在分支,是个引用,指向了refs/heads中当前所在分支
cat config #配置文件
cd refs/tags #标签
cd refs/heads #版本库(哈希值)

11.对象之间的关系【精华】

对象类型有四种:commit、tree、blob、tag

  • 每次提交都会生成一个 commit 对象【相当于一个快照】
  • 一个 commit 对应一棵树tree,【相当于一个文件夹】
  • 只要内容一样,即使文件名不一样,也是同一个文件blob【 hash 值标记】
1
2
git cat-file -t aee370    #查看该哈希值的对象类型【commit、tree、blob、tag】
git cat-file -p aee370 #查看该哈希值的对象内容

这里介绍一篇文章:https://zhuanlan.zhihu.com/p/96631135,讲的很详细。以下是修改一个文件并提交的commit 过程。

12.分离头指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
git checkout 413c5d9b76    #分离头指针(detached HEAD),基于413c5d9b76创建一个没有分支的工作区

###创建一个没有分支的工作区,注意:当切换到其他分支时,此工作区将被当作垃圾丢弃,此处会产生以下提醒:
➜ use_git git:(a0a5992) git checkout master
Warning: you are leaving 2 commits behind, not connected to
any of your branches:

a0a5992 2.txt
35f7cdf 1.txt

If you want to keep them by creating a new branch, this may be a good time
to do so with:

git branch <new-branch-name> a0a5992

Switched to branch 'master'

###此时若要基于此工作区创建新的分支,使用命令可创建新的分支:
git branch <new-branch-name> a0a5992

13.处理紧急任务

  • 在处理 task01 时,需要紧急完成 task02 ,此时需要工作区和暂存区为 clean

  • 解决方案:工作区暂存区已修改的文件 ,放入堆栈中(工作区的新建的文件无法放入,需要先 git add)。

1
2
3
4
5
6
git stash        #将工作区和暂存区的任务放到堆栈中

git stash pop #将文件从堆栈中弹出来,并删除堆栈信息
git stash apply #将文件从堆栈中弹出来,不删除堆栈信息

git stash list #查看堆栈信息

14.不需要git管理的文件

  • 不需要git管理的文件,写入 .gitignore 文件中。
  • .gitignore 文件中 doc 表示 名叫doc的文件名叫doc的文件夹 都不管理
  • .gitignore 文件中 doc/ 表示管理 名叫doc的文件 ,但不管理名叫doc的文件夹下的内容

15.备份与同步

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
# 添加远程仓库(git_name 相当于 地址的别名)
git remote add git_name file://path/.git
git remote add git_name git@github.com:AimTao/use_git.git
# 查看远程仓库
git remote -v
# 删除远程仓库
git remote remove git_name

--------------------------------------------
# 将本地同步到远程仓库
git push git_name --all
git push git_name branch_name

# 将本地当前分支推送至远端仓库的特定分支
# 例:本地当前分支用 HEAD 表示,dev 表示远端仓库的特定分支。
git push remote_repo_name HEAD:dev

--------------------------------------------
# 将远程仓库克隆到本地
git clone --bare file://path/.git new_git_name
git clone git@github.com:AimTao/use_git.git #默认名为远程仓库名
git clone git@github.com:AimTao/use_git.git new_git_name #自定义名称

--------------------------------------------
# 获取(fetch)远端的改动,不合并(merge)
git fetch git_name branch_name
# 获取(fetch)并合并(merge)远端的改动
git pull git_name branch_name

# 「遇到冲突,手动解决的办法一」
# pull 下来的代码,如果不能自动 merge,就会产生一个新的、没有名字的分支,需要手动解决冲突。
# 解决步骤 1 :pull 远端代码,并手动修改冲突文件
# 解决步骤 2 :添加更改的文件
git add change_file
# 解决步骤 3 :基于远端的最新 commit,创建本地修改的多个 commit。
git rebase --continue

# 「集成策略为 18.分支集成策略 中的 (3)Rebase and merge」



# 「遇到冲突,手动解决的办法二」
# 不使用 pull ,使用 fetch + merge
# 解决步骤 1 :fetch 远端代码,并手动修改冲突文件
# 解决步骤 2 :添加更改的文件
git add change_file
# 解决步骤 3 :基于远端的最新 commit,创建本地修改的多个 commit。
git commit -m"merge"

# 「集成策略为 18.分支集成策略 中的 (1)Create a merge commit」
1
remote:遥远的        fetch:取回		merge:合并

16团队协作的场景

(1)不同人同时修改不同区域

1
2
3
4
5
6
7
8
9
10
11
# 1.先把远端的仓库fetch下来
git fetch git_name
# 2.再将本地和远端仓库合并
git merge remote_branch_name
# 3.合并后push到远端仓库
git push git_name branch_name

--------------------------------------------
# 其中 1&2 可以用pull命令代替
# 将远端的仓库pull下来(fetch+merge)
git pull git_name

(2)不同人同时修改同一区域

手动修改该文件,并删掉merge的提示信息

(3)更改文件名对他人影响

1号队员更改文件名并push,2号队员修改内容发现push被reject。

2号队员直接pull即可。

(4)不使用 git push -f

(5)不对公共 commit 做变基

只能对 本地commit 做变基,一旦 push 到远端仓库,就不可以 pull 下来,做变基

(6)打 patch

1
2
git apply xxx.patch
git apply --reject xxxx.patch # 如果有冲突,加上 --reject 参数,会自动合并无冲突部分。

对于无法合入的块,会自动生成一个文件,xxx.rej 文件。手动解冲突后,删除 .rej 文件。

(7)revert change

回退某一笔代码。

1
git revert hash_value

17.工作流

(1)主干开发

(2)Git Flow

复杂,不推荐

(3)Github Flow

在特性分支开发,再集成到 master

(4)GitLab Flow(带生产分支)

在 Github Flow基础上, 用 master 做集成,用 production 来做缓冲,做上线

(5)GitLab Flow(带环境分支)

在上线之前增加环境测试

(6)GitLab Flow(带发布分支)

需要维护不同版本

18.分支集成策略

Github 的 marge 选项

(1)Create a merge commit

将特性分支 merge 到主干分支

(2)Squash and merge

将特性分支的 commit 合成一条 commit 并提交到主干分支,(保留特性分支)

(3)Rebase and merge

将特性分支的 commit 直接复制到主干分支


学习笔记|Git
https://www.aimtao.net/git/
Posted on
2020-03-02
Licensed under