Git 基础知识
常用命令
| 命令 | 简要说明 |
|---|---|
| git clone 仓库地址 | 克隆版本库 |
| git status | 查看状态 |
| git add . | 添加至暂存区 |
| git commit -m '说明' | 提交并添加说明 |
| git push -u origin master | 推送至远程仓库 master 分支 |
| git branch -a | 列出所有分支 |
| git branch dev | 创建 dev 分支 |
| git checkout dev | 切换到 dev 分支 |
| git merge dev | 把 dev 分支合并到 master 分支 |
| git branch -d dev | 删除 dev 分支 |
| git pull origin master | 同步分支到本地 |
| git reset --hard 版本号 | 获取历史版本 |
| git remote add origin xxx | 关联远程仓库 |
基本操作
git init
## 跟踪文件|将改动放入暂存区
# 当前目录下的所有,不包括.gitignore中的文件或目录
git add .
# 指定目录
git add dirPath
# 指定文件
git add filePath
# 指定多个文件
git add file1Path file2Path
# 将改动从暂存区中移除
git restore filename
# 撤销工作区指定文件的修改
# 还原到最近的commit状态
git checkout filename
# 将暂存区的内容提交到本地仓库
git commit -m "you can diy here content"
# 查看工作区当前状态
git status
## 查看commit日志,提交历史
git log
# 带图像的查看
git log --graph
# 查看查看命令历史
git reflog
## 查看指定文件的改动了哪些
git diff filename
# 查看工作区指定的文件与版本库中最新的代码有何区别
git diff HEAD -- filename
## 回退到之前的commit
# tips:
# HEAD表示当前版本
# HEAD^表示前一版本
# HEAD^^表示前两个版本,依次类推
# 当前的修改不会丢弃
git reset HEAD^
# 丢弃当前的更改
git reset HEAD^ --hard
## 删除文件相关
# 从本地仓库中取回被删除的文件
git checkout filename
# 命令本质的作用就是用最新的commit中的文件替换当前的文件
# 从本地仓库中删除指定的文件
git rm filename
# 删除后需要commit过后才生效
git commit -m "del: delete a filename"
# 在commit之前想要恢复的话
# 第一步,先把修改弄到暂存区
git restore --staged filename
# 第二步,撤销暂存区的修改
git restore filename2
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
分支管理
创建和切换
# 创建 dev 分支
git branch dev
# 切换到 dev 分支
git checkout dev
# 创建 dev 分支并切换到 dev 分支
git pull remoteName branchName2
3
4
5
6
7
8
合并分支
# 先切换为 master 分支
git checkout master
# 合并分支 把 dev 分支合并到 master 分支
git merge dev
# 将合并的分支提交到仓库
git push
# 快速合并
# 将otherBranch分支合并到当前的分支
# 快速合并看不出来做过改动
git merge otherBranch
# 合并其它分支,将变动都放入暂存区,不合并commit
git merge otherBranch --squash
# 禁用快速合并
git merge --no-ff -m "commit msg" otherBranch
# 舍弃合并,尝试恢复到你运行合并前的状态
git merge --abort2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
更改分支名
checkout 既可以切换分支又可以撤销修改,容易造成歧义,所以切换分支可以使用switch
# 修改本地分支名称:
git branch -m oldBranchName newBranchName
# 将改名后的本地分支推送到远程,并将本地分支与之关联
git push --set-upstream origin newBranchName
# 删除本地分支
git branch -d branchName
## switch
# 切换分支
git switch branchName
# 创建并切换
git switch -c newBranchName2
3
4
5
6
7
8
9
10
11
12
13
14
合并其它分支的某个commit到当前分支
# 单个commit的cherry-pick
git cherry-pick commit_id
# 多个连续commit的cherry-pick(不包含first_commit_ID)
git cherry-pick first_commit_ID..last_commit_ID
# 多个连续commit的cherry-pick(包含first_commit_ID)
git cherry-pick first_commit_ID^..last_commit_ID
# 多个不连续commit的cherry-pick
git cherry-pick commit_id_1 commit_id_2 commit_id_32
3
4
5
6
7
8
9
10
11
如果在cherry-pick过程中遇到冲突:
- 解决冲突
- 使用
git add添加解决冲突后的文件 - 使用
git cherry-pick --continue继续执行 - 如果想要放弃cherry-pick,使用
git cherry-pick --abort
变基
rebase操作可以把本地未push的分叉提交历史整理成直线
git rebase branchName回溯版本
查看 commit hash 值
git reflog回溯版本
git reset --hard xxxx回溯命令
git push -f配置 Git SSH Key
命令行输入:
ssh-keygen -t rsa -b 4096 -C "邮箱"连续敲击 3 次回车,即可 /c/Users/ 当前用户/.ssh/ 目录中生成 id_rsa 和 id_rsa.pub 两个文件
远程仓库
# 关联远程仓库
git remote add remoteName address
# remoteName 可以自行定义,可以关联多个远程仓库
# 一般主要的remote 使用 origin命名
# 只显示名称
git remote
# 显示远程仓库的地址
git remote -v
# 删除关联的远程仓库
git remote remove remoteName
# 重命名关联的远程仓库
git remote rename oldRemoteName newRemoteName
# 本地分支推到远程仓库
# 全写
git push remoteName localBranchName:remoteBranchName
# 简写(这种情况默认本地与远程分支名称一致)
git push remoteName branchName2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
设置上游分支
git push -u remoteName branchName
# 设置上游分支后
# 本地在push的时候就可以直接执行
git push
# 等价于
git push remoteName branchName
# 克隆远程仓库到本地
git clone remoteAddress
## 更新本地的分支列表
# 更新所有的远程仓库的
git fetch -all
# 更新指定远程仓库
git fetch remoteName
# 拉取/合并远程的分支到本地
git pull remoteName branchName2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
stash
将工作区未提交的内容先存储起来
# flagName 用于标示每次的stash操作
git stash save flagName
# 查看贮藏的列表
git stash list
# 恢复贮藏的内容
git stash pop stash_id
# or
git stash apply stash_id
# stash_id通过git stash list 获取
# 区别
# pop会在恢复后删除指定的stash
# apply不会删除2
3
4
5
6
7
8
9
10
11
12
13
14
标签
给指定的commit打上一个标签,便于寻找关键的commit
# 默认为最新的commit打上tag
git tag v0.0.0
git tag youlikeText
# 为指定的commit 打上tag
git tag youlikeText commit_id
# commit_id通过git log获取
# 创建带有说明的标签
git tag -a tagName -m "description" comment_id
# 查看所有标签
git tag
# 将本地的tag提交到远程仓库
git push --tag2
3
4
5
6
7
8
9
10
11
12
13
14
修改用户名和邮箱
输入命令:
git config --global user.name 'xxxxx'
git config --global user.email 'xxxxx@qq.com'2
合并两个没有共同历史提交记录的分支
某个git仓库原有master分支,后面自己本地新建了一个项目,然后把新建的这个推到了这个仓库的另外一个分支temp 直接合并报错fatal: refusing to merge unrelated histories
解决方案:采用git rebase --onto变基的方法
1.先从master上拉出一个新的分支dev进行操作,并推到远程
git checkout -b dev
git push --set-upstream origin dev //推送并关联远程分支
2.执行git rebase --onto temp进行变基操作 
3.在该分支上拉取允许不相关历史的操作,然后手动解决冲突
git pull --allow-unrelated-histories

4.解决冲突,提交推送到远程
npm config set registry http://registry.npmmirror.com
https://registry.npmjs.org2
3
ssh
ssh-keygen -t ed25519 -C "1395568275@qq.com" -f ~/.ssh/id_ed25519_mcwmengxi
config
# github
Host github.com
HostName ssh.github.com
User mcwmengxi
IdentityFile ~/.ssh/id_ed25519_mcwmengxi
PreferredAuthentications publickey
Port 4432
3
4
5
6
7
sourcetree添加ssh秘钥 ssh -T git@github.com
解除ssh验证
git config --global http.sslVerify false
用户账号管理
如果在项目自己的配置文件中已经有了用户名的配置,则优先使用项目自己的配置。如果项目没有单独配置,则再根据当前根路径是否指定了配置文件去获取对应的配置信息
管理同一目录下的配置
目录下建立.gitconfig
[user]
name = mcwmengxi
email = 1395568275@qq.com2
3
修改git的全局配置文件.gitconfig,把当前目录添加全局配置文件中
[includeIf "gitdir:D:/project/"]
path = D:/project/.gitconfig2
单独配置项目用户名
git config user.name mcwmengxi
git config user.email 1395568275@qq.com2
git代理
.gitconfig文件开启代理,访问github,git仓库走ssh
[http]
proxy = http://127.0.0.1:26501
sslverify = false # 禁用 SSL 安全证书检查2
3
实际场景使用git
ERROR [1] [Sourcetree.Composition.VSMef.Net48.VSMefCompositionManager] [Log] - Unable to load MEF components删除该目录下两个.cache文件 Composition.cache Assemblies.cache
C:\Users\mengxi\AppData\Local\Atlassian\SourceTree.exe_Url_fop3hzd4ikr21gr5nqmqd4tnru2hl5kn\3.4.12.0
移除本地分支与远程的关联
# 1.查看分支的远程关联
git branch -vv
# 2.移除远程关联
git branch --unset-upstream
git branch -vv2
3
4
5
6
7
多个提交合并成一个
# 1.查看提交记录
git log -8 --oneline
# 2.选择合并范围 假设你想要合并最近的四个commits
git rebase -i HEAD~4
# 3.进行交互式变基 在打开的编辑器中,你会看到一列commit列表,每个commit前都有一个命令提示符,默认是pick。要将多个commits合并为一个,你需要将除了第一个commit之外的其他commit前的pick改为squash或者s。这告诉Git要将这些commits与前一个commit合并。
# 4.按esc退出编译模式,按大写ZZ保存并关闭编辑器,Git会开始rebase的过程。如果有需要,它会停下来让你解决合并期间产生的冲突。
# 5.编辑合并后的提交信息 Git将会打开一个新的编辑器窗口,让你编辑最终的提交信息。
# 6.查看合并后日志并推送到远程
git log --oneline
git push --force2
3
4
5
6
7
8
9
10
11
12
13
14
15
风险代码合入回滚
1.风险代码提交了 Commit ,但未推至远程
# 1.撤销提交到暂存区
git log
git reset --soft xxx
# 2.直接撤销
git reset --hard xxx2
3
4
5
6
2.风险代码已经推送至远程分支,但未合入
# 风险代码提交推送到远程
git commit -m "xxxx"
git push
# 直接修复,并覆盖 上次commit
git commit --amend
git push --force-with-lease origin git-reset-test2
3
4
5
6
7
# fatal: The current branch git-reset-test has no upstream branch.
# 该分支没有设置上游分支
git push --set-upstream origin git-reset-test
# 如果您希望 Git 在将来自动为没有跟踪上游的分支设置远程分支,可以配置 push.autoSetupRemote 选项
git config --global push.autoSetupRemote true2
3
4
5
ps: 需要注意的是,这里的强推需要避免使用 git push -f,在多人合作场景下,push -f可能会覆盖其他人的代码,而 push --force-with-lease 是一种更安全的强推做法,如果强推阶段的本地 git tree 落后于远端 git tree,push --force-with-lease会禁止强推,并引导你完成本地内容的同步后再进行后续操作。
存在风险代码的远程分支合入了主分支
如果存在风险的代码分支已经合入了主分支,这种需要第一时间进行回滚止损。与非主分支的回滚不同,主分支应该禁用直接的强推操作,我们需要使用 revert 完成分支的回滚。
git log
# 与reset回滚不同的是,revert会创建一个新的commit用来撤销之前变更的内容,常用于主分支的回滚场景。
git revert xxx2
3
git rebase 让你的提交记录更加清晰可读
1.git rebase 的使用
假设我们现在有2条分支,一个为 master,一个为 feat/1.0.1,他们都基于初始的一个提交 add readme 进行检出分支,之后,master 分支增加了 3.js 和 4.js 的文件,分别进行了2次提交,feat/1.0.1 也增加了 1.js 和 2.js 的文件,分别对应以下2条提交记录。
此时,切换到 feature/1 分支下,执行 git rebase master,成功之后,通过 git log 查看记录。以 master 分支最后的提交作为基点,再逐个应用 feat/1.0.1 的每个更改。

大部分情况下,rebase 的过程中会产生冲突的,此时,就需要手动解决冲突,然后使用依次 git add 、git rebase --continue 的方式来处理冲突,完成 rebase 的过程,如果不想要某次 rebase 的结果,那么需要使用 git rebase --skip 来跳过这次 rebase 操作。
git cherry-pick 冲突时的解决方法也与此类似
2.git rebase 交互模式
合并本地多个重复功能提交, 使git提交记录更简洁
git rebase -i ac18084
想要合并这一堆更改,我们要使用 Squash 策略进行合并,即把当前的 commit 和它的上一个 commit 内容进行合并, 大概可以表示为下面这样,在交互模式的 rebase 下,至少保留一个 pick,否则命令会执行失败。
pick ... ...
s ... ...
s ... ...
s ... ...2
3
4
修改文件后 按下 : 然后 wq 保存退出,此时又会弹出一个编辑页面,这个页面是用来编辑提交的信息,修改为 feat: 更正,最后保存一下
配置 git alias 提升工作效率
更新你全局的 .gitconfig 文件,该文件用来保存全局的 git 配置,vim ~/.gitconfig
[alias]
st = status -sb
co = checkout
br = branch
mg = merge
ci = commit
ds = diff --staged
dt = difftool
mt = mergetool
last = log -1 HEAD
latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
type = cat-file -t
dump = cat-file -p
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
自用的 .gitconfig 配置
[user]
email = nangongfairy@gmail.com
name = youmengyin
[difftool "sourcetree"]
cmd = "'' "
[mergetool "sourcetree"]
cmd = "'' "
trustExitCode = true
[url "https://github.com/guansss/CubismWebFramework.git"]
insteadOf = git@github.com:guansss/CubismWebFramework.git
[gui]
encoding = utf-8
# 代码库统一使用utf-8
[i18n]
commitencoding = utf-8
# log编码
[svn]
pathnameencoding = utf-8
# 支持中文路径
[core]
quotepath = false
# autocrlf = true
[alias]
last = log -1 HEAD
latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
lgs = log --color --graph --pretty=format:'%Cred%h%Creset %C(bold blue)<%an>%Creset %Cgreen(%ar) %C(yellow)%s%Creset'
# 撤销一个commit
undo = reset HEAD~1 --soft
personal = ! git config --global user.name youmengyin && git config --global user.email nangongfairy@gmail.com
company = ! git config --global user.name mochunwang && git config --global user.email mochunwang@company.com
lp = ! git config user.name youmengyin && git config user.email nangongfairy@gmail.com
lc = ! git config user.name mochunwang && git config user.email mochunwang@company.com
uns = ! git branch --unset-upstream2
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
git stash clear/drop 后如何恢复
# 获取所有dangling commits
git log --graph --oneline --decorate $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
# 最新的哈希值
git stash apply efaba9de2
3
4
5
方法2
检查是否还有 stash 引用(最有效)
# 查看所有 stash 记录,包括已删除的
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
# 或者查找所有悬空对象
git fsck --full2
3
4
5
如果找到类似 stash@{0} 的悬空提交,可以:
# 列出所有悬空提交
git log --oneline $(git fsck --no-reflog | awk '/dangling commit/ {print $3}')
# 恢复特定的悬空提交
git stash apply <commit-hash>2
3
4
5
