最近花了一些时间总结了在日常工作中经常使用的 Git 命令,并整理了一些常见问题的解决方法。希望这份总结是全面而实用的,但如果有任何错误或改进的地方,欢迎大家指正。感谢! 🙏
参考文档
基本命令
远程仓库
sh
# 克隆远程仓库
git clone <url>
# 添加远程仓库,origin也可以是其它名称
git remote add origin <url>
# 查看远程仓库
git remote -v
# 删除远程仓库
git remote rm origin
# 推送远程仓库
git push origin master
日常使用
sh
# 初始化
git init
# 添加暂存区
git add <file>
# 或者添加所有
git add .
# 提交本地仓库
git commit -m <message>
# 拉取远程代码到本地
git pull origin <branchName>
# 推送远程仓库
git push origin <branchName>
分支管理
sh
# 查看分支
git branch
# 创建分支
git branch <name>
# 切换分支
git checkout <name> 或者 git switch <name>
# 创建+切换分支
git checkout -b <name> 或者 git switch -c <name>
# 合并某分支到当前分支
git merge <name>
# 删除分支
git branch -d <name>
标签
命令git tag <tagname>
用于新建一个标签,默认为HEAD
,也可以指定一个commit id;
sh
git tag v1.0
# 为指定commit打标签
git tag v0.9 d428d8344
# 指定标签信息
git tag -a v1.1 -m "blablabla..."
# 查看所有标签
git tag
标签操作
sh
# 删除标签
git tag -d v0.1
# 推送标签到远程仓库
git push origin v1.0
# 一次推送所有标签
git push origin v1.0
# 推送指定tag到远程仓库
git push origin v0.1
# 推送所有tag到远程仓库
git push origin --tags
# 删除远程仓库的标签,需要先删除本地的,然后推送到远程
git tag -d v0.9
git push origin :refs/tags/v0.9
撤销修改
git checkout -- a.txt
撤销a.txt的修改,分两种情况:
如果a.txt没有添加到暂存区则回到版本库一模一样的状态
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态
git 建议使用 git restore 命令操作
sh
# 撤销修改了的文件不过没有添加到暂存区
git restore a.txt
# 撤销修改了的文件并且添加到了暂存区,但是还没提交
git restore --staged a.txt
版本回退
sh
# 回退到上一个版本
git reset HEAD^
# 可以使用 --hard 参数强制回退
git reset --hard HEAD^
# 回退到倒数第二个版本
git reset --hard HEAD^^
# 回退到倒数第n个版本
git reset --hard HEAD~n
# 回退到指定commit
git reset commitId
当我们回退到指定版本后,又想回退回来。可以使用 git reflog 查看命令历史,找到commitId,再执行reset即可
reset 适用于代码还没有push到远程仓库的情况,如果代码已push到远程仓库,推荐使用revert
reset是直接回到指定的提交会修改历史记录,而 revert 会新增一次提交并保留之前的记录
cherry-pick 的妙用
cherry-pick
是 Git 中一个强大而灵活的命令,用于将单个提交(或一系列提交)从一个分支应用到另一个分支。这个命令的妙用在于能够选择性地复制某个特定提交,而不是整个分支的更改。
以下是一些 cherry-pick
的妙用场景:
1. 合并特定提交
假设你在 feature-branch
上开发了多个新特性,但只想把其中一个特性合并到 master
分支。你可以使用 cherry-pick
来选择性地合并某个提交:
bash
# 切换到 master 分支
git checkout master
# 找到要合并的特定提交的 commit hash
git log
# Cherry-pick 指定的提交到 master 分支
git cherry-pick <commit-hash>
2. 合并多个提交
如果你不仅想要某个特定提交,还想要它之后的一系列提交,你可以指定一个提交范围:
bash
# 合并一个提交范围(包括 start-commit 和 end-commit)
git cherry-pick start-commit^..end-commit
3. 解决冲突
在某些情况下,cherry-pick
可能会引发冲突,特别是当目标分支上有与要应用的提交相冲突的更改时。在这种情况下,你需要手动解决冲突:
bash
# 在应用提交时解决冲突
git cherry-pick <commit-hash>
# 如果有冲突,手动解决冲突后,继续 cherry-pick
git cherry-pick --continue
4. 移植修复到不同的分支
如果你在一个分支上修复了一个 bug,而希望将这个修复移植到其他分支,可以使用 cherry-pick
:
bash
# 在修复分支上
git checkout -b bug-fix
# 找到修复提交的 commit hash
git log
# Cherry-pick 修复提交到其他分支
git checkout target-branch
git cherry-pick <bug-fix-commit-hash>
5. 整理提交历史
有时候,你可能希望将一个分支上的一系列提交合并成一个更简洁的提交,以使提交历史更加清晰:
bash
# 切换到目标分支
git checkout target-branch
# Cherry-pick 一系列提交到目标分支
git cherry-pick start-commit^..end-commit
# 如果有冲突,解决冲突并继续 cherry-pick
git cherry-pick --continue
cherry-pick
提供了一种非常灵活的方式,可以精确地选择并应用单个提交或一系列提交,使得在 Git 中进行代码管理更加灵活和高效。
Gitflow 完整流程
Gitflow 是一种基于 Git 的分支管理策略,它定义了一种标准的分支模型,帮助团队更有效地协同开发和管理版本。以下是 Gitflow 的完整流程:
1. 分支说明
-
master
分支:- 存储稳定的、发布的版本。
- 从
develop
分支合并而来。
-
develop
分支:- 主要开发分支。
- 所有新特性和bug修复都从这里创建分支。
-
Feature 分支:
- 用于开发新特性。
- 从
develop
分支创建,最终合并回develop
分支。
-
Release 分支:
- 用于发布版本前的准备工作。
- 从
develop
分支创建,最终合并回develop
和master
分支。
-
Hotfix 分支:
- 用于紧急修复在生产环境中发现的 bug。
- 从
master
分支创建,最终合并回master
和develop
分支。
2. 初始化仓库
bash
# 初始化仓库
git init
# 创建并切换到 develop 分支
git checkout -b develop
3. 开发新特性
bash
# 创建并切换到 feature 分支
git checkout -b feature/new-feature develop
# 在 feature 分支上进行开发
# ...
# 将 feature 分支合并回 develop 分支
git checkout develop
git merge feature/new-feature
git branch -d feature/new-feature
4. 发布新版本
bash
# 创建并切换到 release 分支
git checkout -b release/1.0.0 develop
# 在 release 分支上进行版本准备工作(更新版本号、解决 bug)
# ...
# 将 release 分支合并回 develop 和 master 分支
git checkout develop
git merge release/1.0.0
git checkout master
git merge release/1.0.0
# 创建并切换到新的 develop 分支
git checkout -b develop
# 删除 release 分支
git branch -d release/1.0.0
5. 紧急修复
bash
# 创建并切换到 hotfix 分支
git checkout -b hotfix/1.0.1 master
# 在 hotfix 分支上进行紧急修复
# ...
# 将 hotfix 分支合并回 master 和 develop 分支
git checkout master
git merge hotfix/1.0.1
git checkout develop
git merge hotfix/1.0.1
# 创建并切换到新的 develop 分支
git checkout -b develop
# 删除 hotfix 分支
git branch -d hotfix/1.0.1
以上流程就是 Gitflow 的完整模型。它提供了一套清晰的分支管理策略,使团队更容易协作,同时也能够方便地进行版本发布和紧急修复。
常见问题
git fetch 和 git pull 有什么区别
-
git fetch 获取远程仓库的最新变动,但不自动合并到当前分支。
使用 git log 查看commit并没有改变,需要手动 git merge
-
git pull 获取远程仓库的最新变动,并自动合并到当前分支。
使用 git log 可以查看到最新的commit,相当于同时执行了 git fetch 和 git merge
在使用时,git fetch 提供了更大的控制权,因为你可以查看变动并决定是否合并。然而,git pull 是一个更方便的命令,适用于你希望获取最新变动并立即合并到当前分支的情况。
git rebase 和 git merge 的区别(git pull --rebase和 git pull区别)
git rebase
和 git merge
这两个命令旨在将更改代码从一个分支合并到另一个分支,只是两者合并方式不一样。
-
git merge
: 创建一个新的合并提交,将两个分支的历史连接在一起。这会在历史上保留每个分支的所有提交。使用 merge 是很好的方式,因为它是一种非破坏性的操作,现有分支不会以任何方式被更改 另一方面,这也意味着 feature 分支每次需要合并上游更改时候,都会产生一个额外的合并提交。 如果 master 提交非常活跃,这可能会严重污染你的 feature 分支历史记录。不过这个问题可以使用高级选项 git log 来缓解
-
git rebase
: 会将目标分支移动到当前分支的顶端,它会合并master分支上所有新的提交。与merge 提交方式不同,rebase通过为原始分支中的每个提交创建全新的 commits 来重写项目历史记录,特点是仍然会在 feature 分支上形成线性提交。
git pull --rebase和 git pull区别
git pull 默认使用的是merge合并,如果想改为rebase合并需要加上 --rebase 参数
进一步了解Git Rebase vs. Git Merge: 区别
1. Git Merge
-
概念:
- 创建一个新的合并提交,将两个分支的历史连接在一起。
- 保留每个分支的所有提交,形成一个合并的节点。
-
特点:
- 非破坏性操作。
- 对现有分支不会以任何方式进行更改。
-
示意图:
scssA---B---C---D (master) \ E---F---G (feature)
当执行
git merge feature
后:scssA---B---C---D---H (master) \ / E---F---G (feature)
其中,H 是合并提交,保留了 master 和 feature 分支的历史。
2. Git Rebase
-
概念:
- 将目标分支移动到当前分支的顶端,有效地整合所有目标分支上的提交。
- 通过为原始分支中的每个提交创建全新的 commits,形成一个线性提交历史。
-
特点:
- 产生一个整洁的线性提交历史。
- 可以在 feature 分支上形成一个更加紧凑的提交历史。
-
示意图:
scssA---B---C---D (master) \ E---F---G (feature)
当执行
git rebase master
后:scssA---B---C---D (master) \ E'---F'---G' (feature)
其中,E', F', G' 是通过 rebase 创建的全新的 commits,整个历史呈现线性结构。
3. 区别总结
-
Git Merge:
- 产生合并提交,保留原分支的历史。
- 非破坏性,但可能导致分支历史杂乱。
-
Git Rebase:
- 通过创建新的 commits 整合提交历史。
- 形成线性提交历史,更加整洁,但是会改变原有的提交 SHA。
选择使用 git merge
还是 git rebase
取决于项目的具体需求,以及个人或团队对提交历史的偏好。
git reset
和 git revert
的区别
git reset
和 git revert
都是用于撤销提交的 Git 命令,但它们的工作原理和影响是不同的。
git reset
:
-
作用:
git reset
用于移动 HEAD 指针以及分支引用,从而指向指定的提交,可以是之前的某个提交,也可以是当前提交之后的某个提交。 -
影响:
git reset
会修改分支的历史记录,它会移动 HEAD 和分支指针,将它们指向指定的提交。这可能导致已有的提交不再包含在分支中,因此谨慎使用,特别是在已经推送到共享仓库的分支上。 -
使用场景:
- 撤销本地未提交的更改:
git reset --hard HEAD
- 回到过去的某个提交:
git reset --hard <commit-hash>
- 撤销最后一次提交:
git reset --hard HEAD^
- 用于移动分支指针,慎用于公共分支。
- 撤销本地未提交的更改:
git revert
:
-
作用:
git revert
用于创建一个新的提交,该提交撤销之前的提交引入的更改。它不会修改现有的提交历史,而是添加新的提交来反转先前的更改。 -
影响:
git revert
会保留原始的提交历史,同时引入一个新的提交,该提交的更改与要撤销的提交相反。 -
使用场景:
- 撤销已经推送到远程的提交,以保持历史的完整性。
- 回滚某个提交,而不改变分支历史。
- 用于公共仓库和团队协作。
区别总结:
-
git reset
:- 移动 HEAD 和分支指针,修改分支的历史记录。
- 慎用于公共分支,因为可能需要强制推送。
-
git revert
:- 创建新的提交,撤销之前的提交引入的更改。
- 保留原始的提交历史,适用于公共仓库和团队协作。