git知识点和常用操作总结
工作原理
- 工作目录(workspace):持有实际文件。
- 暂存区(index/stage):缓存区,临时保存你改动了的文件索引。
- 本地仓库(repository):保存本地仓库commit。
- 远程仓库(remote):用于团队协作或者作为个人备份。
我们写代码就是修改工作区文件,add之后会暂存到index/stage暂存区(修改了的文件的索引)中,多次add到index后,commit提交到本地仓库完成一次提交,或者说是一次快照。
HEAD^
指 HEAD
的父节点,或者 HEAD~1
。
同理: HEAD^^
== HEAD~2
配置
查看配置
使用 git config --list
。
或者直接查看 .gitconfig
文件:
1 | bat ~/.gitconfig |
下面是我的配置:
1 | [user] |
查看某个仓库的配置:
1 | bat .git/config |
配置全局用户名和邮件
git用户名和邮箱的用途是标识git操作的用户。
1 | git config --global user.name "user name" |
配置命令别名(git alias)
配置:
1 | # 常用的alias |
取消配置:
1 | git config --global --unset alias.co |
除了使用命令配置之外,还可以直接编辑 ~/.gitconfig
的 [alias]
字段来给git命令起别名。
1 | [alias] |
除了git alias之外,像oh my zsh的 ~/.zshrc
文件还从linux alias层面提供了一堆git的别名。
配置代理
迫于 git clone
实在是太慢了,学习了一下怎样配置使其走代理。
[http]
和 [https]
字段用来配置本地代理,1081端口。
- 方法一:使用命令配置
1 | # 配置socks5代理 |
- 方法二:编辑
~/.gitconfig
文件
1 | # 配置socks5代理 |
- 查看代理
1 | git config --global --get http.proxy |
- 取消代理
1 | git config --global --unset http.proxy |
速度飞起~
初始化仓库
1 | # 初始化已存在的目录为git仓库 |
查看仓库状态
1 | git status |
克隆仓库
1 | # 克隆本地仓库 |
添加和提交
从工作区添加文件到暂存区:
1 | # 添加单个文件 |
撤回git add:
1 | git rm --cached <file name> |
提交到 HEAD
并附上提交信息:
1 | # 不附加提交信息 |
commitizen
还可以使用commitizen,可以规范化 git commit
信息以便回溯。
1 | # 安装 |
ref:
- http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
- https://www.jianshu.com/p/36d970a2b4da
推送到远程仓库
1 | # 指定远程仓库名origin和分支名master,参数-u的作用是,以后直接git push即可,不用加origin <branch> |
添加远程服务器
1 | # 下面的origin为远程仓库的默认别名,用以区分不同的远程仓库(一个本地仓库关联多个远程仓库)。 |
如果没有克隆远程仓库,将仓库连接到远程服务器。
这里需要做ssh免密校验。
分支
分支是用来将特性开发绝缘开来的。在你创建仓库的时候, master
是“默认的”分支。在其他分支上进行开发,完成后再将它们合并到主分支上。
创建一个“feature_x”的分支,并切换过去
1 | # 创建分支feature_x并切换到feature_x分支,-b参数表示新建分支,checkout表示切换分支 |
基于某个分支产生新的分支:
1 | git checkout -b new_branch base_branch |
切换回主分支
1 | git checkout master |
再把新分支删除
1 | # 删除分支 |
除非将新分支推送到远程仓库,否则该分支就不对他人所见
1 | git push origin <branch> |
删除远程仓库分支:
1 | git push origin :<branch_name> |
将工作区恢复为暂存区内容:
1 | git checkout -- <filename> |
将master回退到上一次commit:
1 | git reset master^ |
将master回退到指定commit id:
1 | git reset <commit_id> |
将暂存区内容恢复为HEAD内容:
1 | git reset HEAD -- <filename> |
查看所有分支信息
1 | # 查看本地分支 |
更新与合并
更新你的本地仓库至最新改动
1 | git pull |
以在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。
要合并其他分支到你的当前分支(例如 master),执行:
1 | # 默认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 | git fetch origin |
重命名和删除文件
1 | git mv old_name new_name |
更新本地仓库到最新改动(拉取最新)
1 | git pull |
合并多个连续的分支
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 | # 对比所有文件 |
git标签
id通过 git log
查看,只需要写前几位并具有唯一指向性即可。
1 | git tag 1.0.0 <commit_id> |
查看日志
1 | # 查看当前分支的历史 |
我最常用的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 | # 将工作区和暂存区恢复到指定commit,丢弃这个commit之后所有的commit |
git垃圾回收机制
随着cdn仓库commit次数的变多,本地的cdn仓库会越来越占空间。可是我本地cdn仓库的目的只是用来push静态文件到github的cdn仓库,目的不是用来做版本管理,那么怎么释放这些成倍于静态文件大小的本地仓库占用空间呢?
git有gc机制(garbage collection),git会不定时的自动auto gc,它可以将松散的文件压缩。
下面是命令:
1 | git gc |
搭配参数使用:
1 | # 对git仓库进行彻底的清理和优化 |
还有另一个简单粗暴的方法:删除.git目录,重新 git init
仓库,然后重新 commit
1 | rm -rf .git |
上面的方法都试过了发现 git gc --aggressive
比较靠谱。
暂存工作区变动到临时空间
有一种场景是:我们已经add了一些文件到暂存区,而我们的工作区又修改了,这个时候测试提交了一个代码错误需要我们在原来的环境下fix,那么该怎么办呢?
1 | git stash |
这个时候工作区就被清空了,开始做bug fix。
完成修复后再pop就可以恢复之前的工作区:
1 | # apply会保留stash list,而pop不会保留 |
查看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的仓库与上游仓库保持一致
- 先clone已经fork的仓库到本地。
- git remote -av查看分支。
- 添加上游仓库git remote add upstream
- git fetch upstream
- git rebase upstream/
,这里如果是做contribution那就用merge。
pull(拉取并合并) = fetch(拉取) + merge(合并)
工作流
https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md
GUI工具
- sourcetree:支持git和svn。
- vscode
- jetbrains ide