git知识点和常用操作总结

git知识点和常用操作总结

工作原理

  1. 工作目录(workspace):持有实际文件。
  2. 暂存区(index/stage):缓存区,临时保存你改动了的文件索引。
  3. 本地仓库(repository):保存本地仓库commit。
  4. 远程仓库(remote):用于团队协作或者作为个人备份。

数据流

我们写代码就是修改工作区文件,add之后会暂存到index/stage暂存区(修改了的文件的索引)中,多次add到index后,commit提交到本地仓库完成一次提交,或者说是一次快照。

HEAD^HEAD 的父节点,或者 HEAD~1
同理: HEAD^^ == HEAD~2

配置

查看配置

使用 git config --list

或者直接查看 .gitconfig 文件:

1
bat ~/.gitconfig

下面是我的配置:

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
[user]
email = herotiga@vip.qq.com
name = wangwei
[http]
proxy = socks5://127.0.0.1:1086
[https]
proxy = socks5://127.0.0.1:1086
[core]
excludesfile = /Users/wangwei/.gitignore_global
[difftool "sourcetree"]
cmd = opendiff \"$LOCAL\" \"$REMOTE\"
path =
[mergetool "sourcetree"]
cmd = /Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh \"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"
trustExitCode = true
[commit]
template = /Users/wangwei/.stCommitMsg
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
[alias]
dog = log --all --decorate --oneline --graph
st = status
co = checkout
ci = commit
br = branch
unstage = reset HEAD --
last = log -1 HEAD

查看某个仓库的配置:

1
bat .git/config

配置全局用户名和邮件

git用户名和邮箱的用途是标识git操作的用户。

1
2
git config --global user.name "user name"
git config --global user.email "email@example.com"

配置命令别名(git alias)

配置:

1
2
3
4
5
6
7
8
# 常用的alias
git config --global alias.co checkout
git config --global alias.st status
git config --global alias.ci commit
git config --global alias.br branch

# 美化git log输出,实际使用时可以在 git lg 后面加命令参数,如: git lg -10 显示最近10条提交
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 config --global --unset alias.co
git config --global --unset user.name

除了使用命令配置之外,还可以直接编辑 ~/.gitconfig[alias] 字段来给git命令起别名。

1
2
3
4
5
6
7
8
9
10
11
12
[alias]
st = status
ci = commit
co = checkout
br = branch
cf = config
fc = fetch
pl = pull
ps = push
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk

除了git alias之外,像oh my zsh的 ~/.zshrc 文件还从linux alias层面提供了一堆git的别名。

配置代理

迫于 git clone 实在是太慢了,学习了一下怎样配置使其走代理。

[http][https] 字段用来配置本地代理,1081端口。

  • 方法一:使用命令配置
1
2
3
4
5
6
7
# 配置socks5代理
git config --global http.proxy socks5://127.0.0.1:1081
git config --global https.proxy socks5://127.0.0.1:1081

# 配置http/https代理
git config --global https.proxy http://127.0.0.1:1081
git config --global https.proxy https://127.0.0.1:1081
  • 方法二:编辑 ~/.gitconfig 文件
1
2
3
4
5
6
7
8
9
10
11
# 配置socks5代理
[http]
socks5://127.0.0.1:1081
[https]
socks5://127.0.0.1:1081

# 配置http/https代理
[http]
proxy = http://127.0.0.1:1081
[https]
proxy = https://127.0.0.1:1081
  • 查看代理
1
2
git config --global --get http.proxy
git config --global --get https.proxy
  • 取消代理
1
2
git config --global --unset http.proxy
git config --global --unset https.proxy

速度飞起~

初始化仓库

1
2
3
4
5
6
# 初始化已存在的目录为git仓库
cd <repository>
git init

# 创建目录并初始化为git仓库
git init <repository>

查看仓库状态

1
git status

克隆仓库

1
2
3
4
5
6
7
8
# 克隆本地仓库
git clone /path/to/repository

# 克隆远程仓库
git clone username@host:/path/to/repository

# 克隆到指定目录
git clone /path/to/repository path/to/newFolder

添加和提交

从工作区添加文件到暂存区:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加单个文件
git add <filename>

# 添加所有文件
git add *

# 添加本目录,监控工作区,会add所有改动,包括修改和新文件,不包括被删除的文件
git add .

# 是git add --all的缩写,提交所有变化
git add -A

# 仅监控已经被add的文件的改动,不提交新文件
git add -u

撤回git add:

1
git rm --cached <file name>

提交到 HEAD 并附上提交信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 不附加提交信息
git commit

# 附加提交信息
git commit -m 'commit infomation'

# add并commit,不推荐使用
git commit -am 'commit infomation'

# 修改最近一次的commit附加信息
git commit --amend

# 修改commit附加信息
git rebase -i <需要修改附加信息的commit的父节点的commit-id>

commitizen

还可以使用commitizen,可以规范化 git commit 信息以便回溯。

1
2
3
4
5
6
7
8
9
10
11
# 安装
cnpm install -g commitizen

# 先add文件
git add <filename>

# 使用j和k上下选择类型,输入影响范围,输入短描述和长描述
git cz

# 查看commit信息
git log

ref:

  1. http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
  2. https://www.jianshu.com/p/36d970a2b4da

推送到远程仓库

1
2
3
4
5
# 指定远程仓库名origin和分支名master,参数-u的作用是,以后直接git push即可,不用加origin <branch>
git push -u origin master

# 不指定远程仓库名和分支名,只关联了一个远程仓库且只有一个分支则可以使用该命令
git push

添加远程服务器

1
2
3
4
5
# 下面的origin为远程仓库的默认别名,用以区分不同的远程仓库(一个本地仓库关联多个远程仓库)。
git remote add origin <remote-repository>

# 查看remote
git remote -v

img

如果没有克隆远程仓库,将仓库连接到远程服务器。

这里需要做ssh免密校验。

分支

分支是用来将特性开发绝缘开来的。在你创建仓库的时候, master 是“默认的”分支。在其他分支上进行开发,完成后再将它们合并到主分支上。

创建一个“feature_x”的分支,并切换过去

1
2
3
4
5
6
7
8
# 创建分支feature_x并切换到feature_x分支,-b参数表示新建分支,checkout表示切换分支
git checkout -b feature_x

# 上面的代码相当于
# 新建分支
git branch feature_x
# 切换到新建的分支
git checkout feature_x

基于某个分支产生新的分支:

1
git checkout -b new_branch base_branch

切换回主分支

1
git checkout master

再把新分支删除

1
2
3
4
5
# 删除分支
git branch -d feature_x

# 强制删除分支
git branch -D feature_x

除非将新分支推送到远程仓库,否则该分支就不对他人所见

1
2
3
4
git push origin <branch>

# 推送到remote并重命名远端分支名
git push origin local_branch_name:remote_branch_name

删除远程仓库分支:

1
git push origin :<branch_name>

将工作区恢复为暂存区内容:

1
git checkout -- <filename>

将master回退到上一次commit:

1
2
git reset master^
git reset master~5

将master回退到指定commit id:

1
git reset <commit_id>

将暂存区内容恢复为HEAD内容:

1
git reset HEAD -- <filename>

查看所有分支信息

1
2
3
4
5
# 查看本地分支
git branch

# 查看本地和远程所有分支
git branch -av

更新与合并

更新你的本地仓库至最新改动

1
git pull

以在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。
要合并其他分支到你的当前分支(例如 master),执行:

1
2
3
4
5
# 默认ff
git merge <branch>

# 推荐使用这种merge方式,保留了合并时的commit
git merge <branch> --no-ff

在这两种情况下,git 都会尝试去自动合并改动。遗憾的是,这可能并非每次都成功,并可能出现冲突(conflicts)。这时候就需要你修改这些文件来手动合并这些冲突(conflicts)。改完之后,你需要执行如下命令以将它们标记为合并成功:

1
git add <filename>

在合并改动之前,你可以使用如下命令预览差异:

1
git diff <source_branch> <target_branch>

标签

为软件发布创建标签是推荐的。这个概念早已存在,在 SVN 中也有。你可以执行如下命令创建一个叫做 1.0.0 的标签:

1
git tag 1.0.0 1b2e1d63ff

1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。可以使用下列命令获取提交 ID:

1
git log

你也可以使用少一点的提交 ID 前几位,只要它的指向具有唯一性。

替换本地改动

假如你操作失误(当然,这最好永远不要发生),你可以使用如下命令替换掉本地改动:

1
git checkout -- <filename>

此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到暂存区的改动以及新文件都不会受到影响。
假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它:

1
2
git fetch origin
git reset --hard origin/master

重命名和删除文件

1
2
3
git mv old_name new_name

git rm filename

更新本地仓库到最新改动(拉取最新)

1
2
git pull
git pull origin master

合并多个连续的分支

1
git rebase -i

然后再pick多个分支中的一个分支作为base,其他的分支squash(s)既可。

合并分支到当前分支

1
git merge <branch>

如若合并失败,则手动修改文件解决冲突,改完之后,你需要执行如下命令以将它们标记为合并成功:

1
git add <filename>

预览分支差异:

1
git diff source_branch target_branch

对比暂存区和HEAD的差异:

1
git diff --cached

对比工作区和暂存区的差异:

1
2
3
4
5
# 对比所有文件
git diff

# 对于指定文件
git diff -- readme.md css/style.css

git标签

id通过 git log 查看,只需要写前几位并具有唯一指向性即可。

1
git tag 1.0.0 <commit_id>

查看日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查看当前分支的历史
git log

# 查看所有分支历史
git log --all

# 查看所有分支历史(图形化)
git log --all --graph

# 简明显示
git log --oneline

# 输出最近3次的commit
git log -n3

# 查看某个commit的详细信息
git show <commit_id>

# 查看引用日志
git reflog

我最常用的git log是这条:

1
git log --all --decorate --oneline --graph

替换本地改动

假如你操作失误(当然,这最好永远不要发生),你可以使用如下命令替换掉本地改动:

1
git checkout -- <filename>

此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到暂存区的改动以及新文件都不会受到影响。

假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它:

1
git fetch origin
1
git reset --hard origin/master
1
2
# 将工作区和暂存区恢复到指定commit,丢弃这个commit之后所有的commit
git reset --hard <commit-id>

git垃圾回收机制

随着cdn仓库commit次数的变多,本地的cdn仓库会越来越占空间。可是我本地cdn仓库的目的只是用来push静态文件到github的cdn仓库,目的不是用来做版本管理,那么怎么释放这些成倍于静态文件大小的本地仓库占用空间呢?

git有gc机制(garbage collection),git会不定时的自动auto gc,它可以将松散的文件压缩。

下面是命令:

1
git gc

搭配参数使用:

1
2
3
4
5
# 对git仓库进行彻底的清理和优化
git gc --aggressive

# 如果有7000个松散的对象或者50个以上的packfile,git才会进行gc
git gc --auto

还有另一个简单粗暴的方法:删除.git目录,重新 git init 仓库,然后重新 commit

1
2
3
4
rm -rf .git
git init
git add .
git commit -m 'info'

上面的方法都试过了发现 git gc --aggressive 比较靠谱。

暂存工作区变动到临时空间

有一种场景是:我们已经add了一些文件到暂存区,而我们的工作区又修改了,这个时候测试提交了一个代码错误需要我们在原来的环境下fix,那么该怎么办呢?

1
git stash

这个时候工作区就被清空了,开始做bug fix。

完成修复后再pop就可以恢复之前的工作区:

1
2
# apply会保留stash list,而pop不会保留
git stash apply

查看stash:

1
git stash list

.gitignore文件编写

便携 .gitignore 文件用于使得git仓库忽略某些文件。

在git仓库目录下touch一个 .gitignore 既可,然后编写规则。

.gitignore 文件生成:https://www.toptal.com/developers/gitignore

tips

内建的图形化 git:

1
gitk

彩色的 git 输出:

1
git config color.ui true

显示历史记录时,每个提交的信息只显示一行:

1
git config format.pretty oneline

交互式添加文件到暂存区:

1
git add -i

rebase

rebase用于将当前分支移动到目标分支的最后一次commit。

rebase黄金法则:不要在公共分支上面使用rebase,比如master。

使用merge还是rebase

看团队而定。

revert

在公共分支使用git revert以保留commit以便回溯,在特性分支使用git reset既可。

将fork的仓库与上游仓库保持一致

  1. 先clone已经fork的仓库到本地。
  2. git remote -av查看分支。
  3. 添加上游仓库git remote add upstream
  4. git fetch upstream
  5. git rebase upstream/,这里如果是做contribution那就用merge。

pull(拉取并合并) = fetch(拉取) + merge(合并)

工作流

https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md

GUI工具

  1. sourcetree:支持git和svn。
  2. vscode
  3. jetbrains ide

扩展阅读

  1. https://juejin.im/post/6844904191203213326

评论