Skip to content
文章目录

git 操作指南

前置概念说明

  • 工作区: 工作区就是你实际看到的目录/文件, 当添加/修改/删除了东西,工作区就会改变
  • 缓存区: git add操作就是将工作区中的内容提交到缓存区
  • 本地仓库: git commit操作就是将缓存区的内容提交到本地仓库
  • 远程仓库: git push就是将本地仓库的内容推送到远程仓库
  • origin: 远程仓库的别名,如果不特殊指定,默认就是这个名字。如: git merge origin/master 这个命令的意思就是合并 orgin 代指的那个远程仓库的 master 分支代码,到当前分支

git push -ugit 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 之后要做什么操作?

  1. 比较当前分支的代码和远程仓库的差异
shell
git log -p master..origin/master
  1. 将远程仓库的代码合并到当前分支
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;

  1. 张三基于 Master,拉了一个分支:Dev1,其最新 CommitId 是 G1,其中 fileA 和 fileB 的内容没有变更;
  2. 李四也基于 Master,拉了一个分支:Dev2,其最新 CommitId 是 P1,其中 fileA 和 fileB 的内容也没有变更;
  3. Dev1 分支,做了一次 commit,ID 是 G2,其中把 fileA 和 fileB 的内容都做了变更(fileA 变成 AAA1,fileB 变成 BBB1);
  4. Dev2 分支,希望能将 Dev1 的代码 Merge 过来,但只想要 fileB 的改动,而暂时不需要 fileA 的改动,于是他执行 git merge Dev1,然后 rollback 了其中 fileA 的变化,提交,commitId 为 P2;
  5. Dev1 分支发布,代码被合并到了 Master,此时 Master 的 CommitId 为 M2,并且 fileA 和 fileB 内容都以 Dev1 的 G2 为准(即 fileA 是 AAA1,fileB 是 BBB1);
  6. Dev2 继续开发,然后等 Dev2 自己也准备要发布了,于是他执行 git merge master 合并最新主干代码(CommitId 是 P3)。此时他以为 fileA 的内容会被改成 AAA1,因为 Master 上就是 AAA1,但其实因为之前 merge Dev1 时,fileA 被自己人工改过了,所以会以自己版本为准,即实际内容还是 AAA。此时 Dev2 的代码已经有问题了;
  7. 最后 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}: 】这里操作时把代码搞丢了

  1. 执行命令: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 不能显示中文

原因: 在默认设置下,中文文件名在工作区状态输出,中文名不能正确显示,而是显示为八进制的字符编码。

解决办法:

  1. git config --global core.quotepath false
  2. 如果配置完第一步,中文从 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 仓库是否有什么限制,另外,可以参考下以下的这些文章,或许有帮助

gitee 上传大小超过 100M 文件

聊聊 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

参考资料

git 中工作区,缓存区,本地库,远程库的简要区别

git pull 和 git fetch 到底有什么区别

git fetch 详解

Git 使用不当导致代码丢失的 N 种场景

Git push 提交后,本地代码丢失找不到解决方法

git fetch 后怎么比较差异