git 操作指南
前置概念说明
- 工作区: 工作区就是你实际看到的目录/文件, 当添加/修改/删除了东西,工作区就会改变
- 缓存区:
git add操作就是将工作区中的内容提交到缓存区 - 本地仓库:
git commit操作就是将缓存区的内容提交到本地仓库 - 远程仓库:
git push就是将本地仓库的内容推送到远程仓库 - origin: 远程仓库的别名,如果不特殊指定,默认就是这个名字。如:
git merge origin/master这个命令的意思就是合并 orgin 代指的那个远程仓库的 master 分支代码,到当前分支
git push -u和git push区别
git push 的命令格式:
shell
git push <远程主机名> <本地分支名>:<远程分支名>
git push 是<本地分支名>:<远程分支名>, 而 git pull 顺序的写法刚好相反是 <远程分支>:<本地分支>
如果省略远程分支名,则表示将本地分支推送与之存在”追踪关系”的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
shell
git push origin master
上面命令表示,将本地的 master 分支推送到 origin 主机的 master 分支。如果后者不存在,则会被新建。
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
shell
git push origin :master
# 等同于
git push origin --delete master
上面命令表示删除 origin 主机的 master 分支。
如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。
shell
git push origin
上面命令表示,将当前分支推送到 origin 主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
git push
如果当前分支与多个主机存在追踪关系,则可以使用-u 选项指定一个默认主机,这样后面就可以不加任何参数使用 git push。
git push -u origin master
上面命令将本地的 master 分支推送到 origin 主机,同时指定 origin 为默认主机,后面就可以不加任何参数使用 git push 了。
不带任何参数的 git push,默认只推送当前分支,这叫做 simple 方式。此外,还有一种 matching 方式,会推送所有有对应的远程分支的本地分支。Git 2.0 版本之前,默认采用 matching 方法,现在改为默认采用 simple 方式。
还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用–all 选项。
shell
git push --all origin
上面命令表示,将所有本地分支都推送到 origin 主机。
如果远程主机的版本比本地版本更新,推送时 Git 会报错,要求先在本地做 git pull 合并差异,然后再推送到远程主机。
git push 不会推送标签(tag),除非使用–tags 选项。
shell
git push origin --tags
tag 操作
将本地 tag 推送到服务器
shell
git push origin --tags
创建 tag
shell
git tag -a 1.0.0 -m "写一点信息作为当前tag的简介"
显示所有 tag
shell
git tag -l
使用 git show 查看 tag 的内容
git tag 1.0.0
删除 tag
shell
git tag -d tag-name
如:
删除本地 tag git tag -d v0.1.2
删除远程的 tag git push origin :refs/tags/v0.1.2
实际应该用 git fetch 还是 git pull?
推荐git fetch
git fetch 与 git pull 区别

| 操作 | 相同点 | 不同点 |
|---|---|---|
| git pull | 拉取远程仓库代码到本地 | 拉取到本地仓库之后,再自动执行 git merge 到工作区 |
| git fetch | 拉取远程仓库代码到本地 | 仅仅是将改变拉取到本地仓库,不会自动git merge到工作区 |
git fetch
命令解释
git fetch: 会从远程仓库拉取当前项目的所有分支的,所有的 commit,如果网速慢,那可能会等很久,不建议这样使用
git fetch origin branch: 设定当前分支的 FETCH_HEAD' 为远程服务器的 branch 分支。建议用该方式
git fetch origin branch1:branch2: 使用远程 branch1 分支在本地创建 branch2(但不会切换到该分支),如果本地不存在 branch2 分支, 则会自动创建一个新的 branch2 分支,如果本地存在 branch2 分支, 并且是`fast forward', 则自动合并两个分支, 否则, 会阻止以上操作.
git fetch origin :branch2: 等价于: git fetch origin master:branch2
git fetch 之后要做什么操作?
- 比较当前分支的代码和远程仓库的差异
shell
git log -p master..origin/master
- 将远程仓库的代码合并到当前分支
shell
git merge origin/master
Git 使用不当导致代码丢失的 N 种场景
强制 Push
触发方式: 在多人并行开发同一个分支时,某人写完代码,git push,如果此时该分支已经也被别人改过且 push 过了,则会提示这个信息:

此时不熟悉 git 的同学,可能会通过加 -f 参数,强制 push:
shell
git push -f origin branchA
或者在 IDEA 里面,选择了 Force Push:

这样之前别人已经 push 的代码,就被丢掉了(因为将会以你本地非最新的代码为准)。并且远程仓库的 git 提交记录也会丢失(可以试试 git reflog 看能不能找回记录)
正确操作: push 代码遇到本地不是最新时,不要强制 push!务必先 git pull 拉最新代码,如果遇到冲突则解决冲突,解决完再 git push。
Merge 时错误处理冲突
触发方式: 在自己的分支上开发,然后需要将其它分支(例如 master)的代码 merge 过来时,遇到了代码冲突,此时处理完冲突后,push 代码,如果没有发生冲突的其它分支文件,没有同时也勾选 push 的话,则代码也会丢失。
如: 在 dev 分支上修改了 Tester.java 文件和其它内容,merge master 提示其中 Tester.java 有冲突;

正确操作: merge 后遇到冲突,解决完冲突后,不要部分提交!push 时务必把所有修改文件都勾选,再 push。这个对于 IDEA 这种图形化界面容易犯错。对于命令行,其实 merge 冲突后,未冲突的文件,是默认已经放入暂存区了,所以 git push 时这些未冲突文件就会一起被正确 push 上去。
附加说明: 这种代码丢失最终在 idea 卡顿时出现,因为卡顿导致你以为勾选了所有文件,但实际有部分文件未勾选,然后你 commit 之后又 push 了
错误使用 Merge
有的时候可能遇到这种情况:自己的开发分支,需要将其他开发分支上的改动 merge 过来,但是只需要其中部分功能,此时如果使用 git merge 的话,就可能会存在问题。
例如下面这个例子:
主干 Master 上有两个文件:fileA 和 fileB。其中 fileA 的内容是 AAA,fileB 的内容是 BBB。最新的 CommitId 是 M1;
- 张三基于 Master,拉了一个分支:Dev1,其最新 CommitId 是 G1,其中 fileA 和 fileB 的内容没有变更;
- 李四也基于 Master,拉了一个分支:Dev2,其最新 CommitId 是 P1,其中 fileA 和 fileB 的内容也没有变更;
- Dev1 分支,做了一次 commit,ID 是 G2,其中把 fileA 和 fileB 的内容都做了变更(fileA 变成 AAA1,fileB 变成 BBB1);
- Dev2 分支,希望能将 Dev1 的代码 Merge 过来,但只想要 fileB 的改动,而暂时不需要 fileA 的改动,于是他执行 git merge Dev1,然后 rollback 了其中 fileA 的变化,提交,commitId 为 P2;
- Dev1 分支发布,代码被合并到了 Master,此时 Master 的 CommitId 为 M2,并且 fileA 和 fileB 内容都以 Dev1 的 G2 为准(即 fileA 是 AAA1,fileB 是 BBB1);
- Dev2 继续开发,然后等 Dev2 自己也准备要发布了,于是他执行 git merge master 合并最新主干代码(CommitId 是 P3)。此时他以为 fileA 的内容会被改成 AAA1,因为 Master 上就是 AAA1,但其实因为之前 merge Dev1 时,fileA 被自己人工改过了,所以会以自己版本为准,即实际内容还是 AAA。此时 Dev2 的代码已经有问题了;
- 最后 Dev2 分支发布,代码被合并到了 Master,其 CommitID 是 M2,其中 fileA 的内容也在主干里面被丢失了,导致故障。
处理完 Tester.java 的冲突后,在 IDEA 里面准备 push 代码,此时展现了有修改的文件列表(如下图)。此时列表内不仅有自己在 dev 分支里面修改的代码,还有被合并过来的分支(master)修改的文件(图中 ClassA 和 ClassB)。
正确操作: 出问题的点在 Dev2 的 Commit P2。对于这种希望将其它分支上的部分改动(例如某几个 commit)移动到自己分支上的情况,强烈建议是不要使用 git merge,而是使用 cherry-pick 将这几个 commit 合并过来。git cherry-pick 教程
Git push 提交后,本地代码丢失找不到解决方法
1.执行命令:git reflog
发现是 【 4214952 (购物车+收藏+订单) HEAD@{3}: 】这里操作时把代码搞丢了

- 执行命令:
git reset --hard HEAD@{3}
出现 HEAD is now at 4de5b02 购物车+收藏+订单 这类型字样就说明你丢失的代码找回来了

git log 和 git reflog 的区别
git log: 显示所有提交过的版本信息,不包括已经被删除的 commit 记录和 reset 的操作 git reflog: 是显示所有的操作记录,包括提交,回退的操作。一般用来找出操作记录中的版本号,进行回退。
git log 除了能查看日志之外,还能比较两个分支中一个分支存在而另一个分支不存在的日志,git log 操作详细请看: git log 与 git reflog 查看历史记录
git reflog 常用于恢复本地的错误操作。
如果希望 git log 的信息也和 git reflog 的一样简洁,那使用git log --oneline
git reset 和 git revert 区别
git reset 用于回滚 commit
- git reset --soft // 回退到指定 commit,该 commit 之后的提交内容,保留工作目录,并把重置 HEAD 所带来的新的差异放进暂存区
- git reset --hard // 回退到指定 commit,该 commit 之后的提交内容,工作区和暂存区的内容都被抹掉
- git reset 或 git reset --mixed // 不带参数,或带参数–mixed(默认参数),与 git reset --soft 不同,它将会把差异放到工作区
如果你只是因为想修改下 commit 信息或发现某次 commit 少提交了一些内容,你需要补全,但不想对相同的修改形成多次 commit 提交记录,那就应该使用git reset --soft 进行回退到指定 commit, 这样你的工作区中,还会有这次 commit 之后做的修改,你改完内容,再次 commit 就可以了
如果你就是想完全删除某次 commit 的变更以及该 commit 之后的所有变更,那就用git reset --hard
如果 git reset 的 id 是已经存在于远程仓库了,那此时如果 reset 成功, 那再 push 的时候,会要强制推送,才会生效。而强制推送,又可能导致其他人 push 的代码丢失,那此时更好的方式应该使用 git revert
git reset 是删除某次 commit 记录,而 git revert 是 commit 的记录时的状态恢复到当前工作工作空间,需要你修改之后再次 commit,原来那个 commit 记录还是存在的,因此 push 的时候无需强制推送,只需普通推送即可,不存在导致其他人代码丢失的风向
如何合并几个历史 commit
使用 git reset 实现,
注意: 只建议在对还没 push 到远程仓库的 commit 进行该操作,如果 reset 了已在远程仓库的 commit id,那 push 就必须使用强制 push 了,这可能会造成,其他人的代码丢失
如何修改历史提交的 message
如何将某个分支的某次 commit 移到另一个分支
使用 cherry-pick 操作 git cherry-pick 教程
你一个需求正做了一半,突然领导给你安排了一个紧急需求咋整?
不优雅的方式 : 在另外一个目录 clone 一份项目代码,新建一个分支,做完之后,再提交推送到远程仓库,然后再删除这个目录下的项目代码,继续回原目录那个项目接着写之前那个需求
优雅的方式: 使用git stash缓存还未开发完毕的代码,待紧急需求开发完毕,再恢复缓存的内容继续开发
注意git stash只会缓存已经git add 但还未 git commit的内容,对于未git add的内容不会缓存
shell
# 给这次缓存加上注释
git stash save "xxx"
# 返回缓存列表
git stash list
# 将堆栈中最新的内容pop出来应用到当前分支上,且会删除堆中的记录
git stash pop
# 将指定缓存的内容应用到当前工作区
git stash apply HASH_ID
# 删除指定缓存的记录
git stash drop HASH_ID
# 清空缓存列表
git stash clear
解决 git status 不能显示中文
原因: 在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码。
解决办法:
git config --global core.quotepath false- 如果配置完第一步,中文从 8 禁止字符变成了中文乱码,那么需要将终端的语言设置为中文,字符集设置为 utf-8
解決 error: RPC failed; curl 55 OpenSSL SSL_write: Connection was aborted, errno 10053
错误原因: 同步数据过大
解决方式: 更改 Git 默认限制推送的大小,增加缓冲
全局設置
shell
git config --global http.postBuffer 524288000
只对当前项目设置
shell
git config http.postBuffer 524288000
如果上述设置还是不成功
shell
git config http.sslVerify "false"
查看当前 git 配置
git config --list
如果进行了以上配置还不能成功,换成移动网络试试,有可能是你当前网络存在问题。如果换了几个网络,依然是同样的问题,那看你的 git 仓库是否有什么限制,另外,可以参考下以下的这些文章,或许有帮助
聊聊 git push 到远程服务器出现 RPC failed 问题
git 提交失败提示 fatal:The remote end hung up unexpectedly
GitHub git push 超过 100MB 大文件失败(write error: Broken pipe)完美解决
git 推送出现 The remote end hung up unexpectedly