Git 使用手册

by Web全栈工程师 on 2016 年 06 月 24 日

1, git fetch 和 git pull 之间的区别

  • git fetch只下载,不合并。它从远程仓库获取最新的数据,让你可以在本地查看这些变更,但不会动你当前的工作。这是一个相对“安全”的操作。
  • git pull下载并合并。它等同于 git fetch + git merge。它会抓取远程的变更,并立刻尝试将这些变更合并到你当前所在的本地分支中。

2, 当想要撤销上一次的提交(commit)时,可以使用git reset 和 git revert 之间的区别

git reset 会重置工作区,这只在特定模式下(--hard)成立。git reset 的核心作用是移动当前分支的 HEAD 指针到另一个提交。它有三个主要模式:

  • --soft:只移动 HEAD 指针。你的工作区和暂存区(index)的改动都还保留着。
  • --mixed(默认模式):移动 HEAD 指针,并且重置暂存区。你的工作区代码不变,但所有改动都变为“未暂存”状态。
  • --hard:移动 HEAD 指针,重置暂存区,并且重置工作区。这是一个比较危险的操作,因为它会丢弃你所有未提交的本地改动。

而 git revert 并非简单地“重置记录”。它实际上会创建一个新的提交,这个新提交的内容刚好是你想撤销的那个提交的反向操作。它并不会删除或修改旧的提交历史。

所以,它们最关键的区别在于:

  1. 历史记录git reset 会改写历史(特别是 reset --hard),让之前的提交看起来像从未发生过。而 git revert 则是通过新增一个提交来“抵消”之前的提交,它会保留完整的历史记录。
  2. 协作安全:正因为 revert 不会改变历史,所以它对于已经推送到远程的、多人协作的分支是安全的。而 reset 一个公共分支,会给其他团队成员带来巨大的麻烦,因为你们的历史记录会产生分叉。

简单来说:

  • git reset 就像是坐上时光机回到过去,抹掉了某个时间点之后的所有痕迹。适用于你自己的私有分支
  • git revert 就像是发现做错了一件事,然后你再做一件相反的事来弥补。适用于公共的协作分支

3,  git stash以及使用场景

git stash 的核心作用:

  1. 暂存(Stash):它会把你当前工作目录和暂存区(Staging Area)中所有未提交的修改(包括已暂存和未暂存的)保存到一个临时的“储藏栈”中。
  2. 恢复(Clean State):执行 stash 后,你的工作目录会变得干净,就像刚执行完 git checkout 一样,没有任何修改。这让你能毫无顾虑地切换分支、拉取更新或执行其他操作。
  3. 取回(Pop/Apply):当你处理完其他事情,切回原来的分支后,可以使用 git stash pop 或 git stash apply 来恢复之前储藏的修改。
  • git stash pop:恢复储藏并从储藏栈中删除该记录。
  • git stash apply:恢复储藏但保留该记录在储藏栈中,方便你应用到其他分支。

总的来说,git stash 是一个强大的工具,用于处理“工作进行到一半被打断”的场景,让你能快速切换上下文,而不用为了切换分支而创建不完整的提交。

4,  git cherry-pick以及使用场景

git cherry-pick 命令的作用就是,将指定的提交(commit)“摘取”过来,应用到当前的分支。

这个过程,它实际上是复制了这个提交的变更内容,然后在当前分支上创建一个全新的提交。这个新提交会拥有一个新的 commit hash,但默认会保留原提交的作者和提交信息。

最典型的使用场景包括:

  1. 紧急修复(Hotfix):假设你在一个已经发布的 release 分支上修复了一个紧急的 bug,这个修复只有一个 commit。但你的开发团队正在 develop 分支上进行新功能开发,也需要这个修复来避免同样的问题。这时,你就可以用 cherry-pick 把那个修复 bug 的 commit 单独应用到 develop 分支,而无需合并整个 release 分支。
  2. 选择性地合并功能:你在一个功能分支 feature-A 上提交了好几个 commit,但现在另一个分支 feature-B 只需要其中一个 commit 所带来的改动。使用 cherry-pick 就可以精确地只把那一个 commit 的变更带过来。
  3. 从错误的分支恢复:你不小心在 main 分支上做了一个本应在 feature 分支上的提交。你可以: a. 切换到 feature 分支,cherry-pick 那个错误的提交。 b. 切换回 main 分支,使用 git reset 移除那个错误的提交。

所以,总的来说,cherry-pick 就像一个精确的手术刀,能够精确地复制单个提交,而不是像 merge 或 rebase 那样对整个分支进行操作。

5, git rebase 和 git merge 的区别

git merge (合并)

git merge 做的事情很简单:它将两个分支的最新快照(C3 和 C4)以及它们共同的祖先(C2)进行三方合并,然后创建一个新的、唯一的“合并提交” (Merge Commit)

过程图示:

假设你的历史记录是这样的:

Code
      A---B---C   (feature 分支)
     /
D---E---F---G   (main 分支)

在 main 分支上执行 git merge feature 后,会变成这样:

Code
      A---B---C
     /         \
D---E---F---G---H   (main 分支, H 是合并提交)

特点:

  • 保留历史:它会忠实地记录下历史,合并提交 H 非常清楚地表明了“在 G 这个节点,我们把 C 的内容合并了进来”。你的提交历史图会是一个有分叉、有合并的网络图。
  • 非破坏性操作:它不会改变现有分支的任何提交,只是在目标分支上新增一个提交。
  • 安全简单:对于已经推送到远程的公共分支,使用 merge 是安全的。

git rebase (变基)

git rebase 的目标不同,它旨在创造一个更线性的提交历史。它会把你当前分支(feature)的所有提交,一个一个地在目标分支(main)的最新提交后面“重放”一遍。

过程图示:

同样,假设你的历史记录是这样的:

Code
      A---B---C   (feature 分支)
     /
D---E---F---G   (main 分支)

在 feature 分支上执行 git rebase main 后,会变成这样:

Code
                  A'--B'--C'  (feature 分支)
                 /
D---E---F---G   (main 分支)

发生了什么?

  1. Git 会找到 feature 分支和 main 分支的共同祖先 E
  2. 它会“暂存”feature 分支独有的提交(ABC)。
  3. 然后,它将 feature 分支的指针移动到 main 分支的最新提交 G 上。
  4. 最后,它把暂存的提交 ABC 重新一个一个地应用在 G 后面,创建出内容相同但 hash 值全新的提交 A'B'C'

特点:

  • 线性历史:最终的提交历史是一条直线,看起来非常整洁,好像所有开发都是按顺序依次进行的。
  • 重写历史rebase 会丢弃原始的提交(A, B, C),并创建全新的提交(A’, B’, C’)。这是一个破坏性的操作。
  • 风险绝对不要在已经推送到远程的公共分支上执行 rebase。因为你重写了历史,如果其他团队成员基于旧的历史进行了开发,当他们拉取你的新历史时,会造成巨大的混乱。

总结与对比

特性 git merge git rebase
历史记录 保留真实的分支与合并历史,非线性 重写历史,使其变为线性,更整洁
新提交 创建一个额外的合并提交 不创建合并提交,但会创建新的常规提交
协作 对公共分支安全 危险,只应该在自己的私有分支上使用
冲突解决 在最后只解决一次所有冲突 在重放每个提交时,都可能需要解决冲突

应该用哪个?

这很大程度上取决于团队的开发规范,但一个普遍被接受的最佳实践是:

  1. 从公共分支拉取更新时,使用 rebase: 当你自己的 feature 分支落后于 main 分支时,你可以在你的 feature 分支上执行 git pull --rebase origin main (或者先 git fetch, 再 git rebase origin/main)。这能让你的分支保持在 main 分支的最新位置,避免了将来合并时产生不必要的合并提交。
  2. 将功能合并到公共分支时,使用 merge: 当你的 feature 分支开发完成,准备合并回 main 分支时,切换到 main 分支,执行 git merge feature。这会保留该功能分支的完整上下文,并通过一个合并提交清晰地记录这次集成。

简单来说:用 rebase 来“追赶”主干道的进度,用 merge 来“汇入”主干道。rebase 只用于尚未分享给别人的本地分支。

“本地用 rebase,合并用 merge 是一个非常流行且高效的工作流。它既能让你在开发时保持清晰的思路,又能让主干历史忠实地记录每一次功能的集成。

6,

原创文章,转载请注明:转载自Web开发笔记 | Git 使用手册

本文链接地址:https://www.magentonotes.com/git-faq.html

Comments on this entry are closed.

Previous post:

Next post: