Git易混淆知识点

153 阅读7分钟

引言

Git 作为目前最为流行的版本控制系统之一,拥有众多的命令和操作,其中一些易混淆的知识点可能会给 Git 的使用者带来不必要的困扰和错误。本文将围绕 Git 中容易混淆的几个知识点,详细解释它们之间的区别和使用场景,希望能够帮助读者更好地理解和运用 Git。

git rebase & git merge

  • git rebasegit merge 都是用于合并代码的 Git 命令,它们的主要区别在于合并的方式不同。
    • git merge 命令会将两个或多个分支的历史记录合并为一个新的提交,并创建一个新的合并提交来合并这些分支。这个新的合并提交有两个或多个父提交。Git 会自动将这些父提交中的差异合并到新的合并提交中。因此,git merge 命令将不同分支上的修改集成到一个新的提交中。
    • git rebase 命令会将当前分支的提交“重新应用”到另一个分支的顶部,从而将两个分支合并为一个。简而言之,它是将当前分支的历史记录“重新排序”,使其基于另一个分支的顶部。这样,当前分支的提交会成为另一个分支的直接后代,而不是一个新的合并提交。使用 git rebase 命令可以使 Git 日志更加干净,因为它可以创建一个线性的提交历史,而不是包含合并提交的分支历史。
  • 假设我们有两个分支:featuremaster,并且它们的提交历史如下:
        A---B---C feature
       /
    D---E---F---G master
    
    
    其中,ABCfeature 分支上的提交,DEFGmaster 分支上的提交。
    • 使用 git merge

      • 首先,我们使用 git merge 命令将 feature 分支合并到 master 分支上。执行如下命令:
        git checkout master
        git merge feature
        
      • 执行完这两个命令后,master 分支的提交历史变为:
            A---B---C feature
           /         \
        D---E---F---G---H master
        
      • 其中,H 是一个新的合并提交,它包含了 feature 分支和 master 分支上的所有差异。
    • 使用 git rebase

      • 接下来,我们使用 git rebase 命令将 feature 分支“重新应用”到 master 分支上。执行如下命令:
        git checkout feature
        git rebase master
        
      • 执行完这两个命令后,feature 分支的提交历史变为:
                A'--B'--C' feature
               /
        D---E---F---G master
        
      • 其中,A'B'C' 是重新应用到 master 分支上的 feature 分支上的提交,它们的内容与原来的提交 ABC 相同,但它们的父提交是 master 分支上的提交,而不是原来的 feature 分支上的提交。
      • 最后,我们将 feature 分支合并到 master 分支上。执行如下命令:
        git checkout master
        git merge feature
        
      • 执行完这两个命令后,master 分支的提交历史变为:
                A'--B'--C' feature
               /             \
        D---E---F---G---------H' master
        
      • 其中,H' 是一个新的合并提交,它包含了 feature 分支和 master 分支上的所有差异。但是,与使用 git merge 命令合并分支时不同的是,使用 git rebase 命令合并分支后,提交历史是线性的,不包含合并提交。

      需要注意的是,使用 git rebase 命令重新应用分支时可能会导致冲突,因此需要手动解决冲突。因此,在实际使用时,需要根据具体情况选择合适的命令。

  • 总体来说,git merge 用于将不同分支的修改集成到一个新的提交中,而 git rebase 用于将一个分支的提交“重新应用”到另一个分支的顶部,从而创造一个更加干净的线性提交历史。需要注意的是,在使用 git rebase 命令时,可能需要手动解决冲突,因为 git rebase 命令会将当前分支的提交“重新应用”到另一个分支的顶部,这可能会导致提交的顺序不同,从而导致冲突。

git fetch & git pull

  • git fetchgit pull 都是用于将远程代码仓库中的代码更新到本地仓库中。它们的区别如下:
    • git fetch 仅仅将远程代码仓库中的最新代码下载到本地仓库,但不会自动将本地代码库中的代码与远程仓库合并。因此,可以使用 git fetch 命令来查看远程仓库中最新的代码,然后再手动使用 git merge 或者 git rebase 命令来将本地代码库中的代码与远程仓库合并。
      • 假设本地仓库中有一个名为 origin 的远程仓库,我们可以使用 git fetch 命令从远程仓库下载最新代码,执行如下命令:
        git fetch origin
        
        上述命令会将 origin 远程仓库中最新的代码下载到本地,但是不会应用到本地分支上。
    • git pull 命令则是将远程代码仓库中的最新代码下载到本地仓库,并自动将本地代码库中的代码与远程仓库合并,就是说,它相当于依次执行了 git fetchgit merge 命令。如果本地代码库中有未提交的修改,git pull 命令会尝试自动合并这些修改。如果自动合并失败,需要手动解决冲突并提交。
      • 假设本地仓库中有一个名为 origin 的远程仓库,我们可以使用 git pull 命令从远程仓库下载最新代码,并将本地分支自动合并到远程分支,执行如下命令:
        git pull origin master
        
        上述命令会从 origin 远程仓库下载 master 分支的最新代码,并将本地的 master 分支自动合并到远程分支。

      需要注意的是,使用 git pull 命令可能会导致合并冲突,因此在实际使用中需要谨慎。如果你不确定是否要合并远程分支,可以先使用 git fetch 命令查看远程分支的更新情况,然后再决定是否要合并。

  • 综上所述,git fetchgit pull 的主要区别是 git fetch 只是将最新代码下载到本地仓库,不会自动合并,而 git pull 会将最新代码下载到本地仓库并自动合并。因此,如果只想查看远程代码库中的最新代码,可以使用 git fetch 命令;如果想将最新代码下载到本地并立即合并,请使用 git pull 命令。

git reset & git revert

  • git resetgit revert 都是 Git 中撤销操作的命令,但它们的执行方式和结果是不同的。
    • git reset 命令可以将当前分支的指针(HEAD)移动到指定的提交(commit),并将暂存区和工作区恢复到该提交的状态。使用 git reset 命令会永久性地删除一些提交记录,因此需要谨慎使用。
      • 常用的几种 reset 模式:
        • git reset --soft:只移动 HEAD 指针,不改变暂存区和工作区的状态。
        • git reset --mixed:移动 HEAD 指针,并将暂存区的内容恢复到指定的提交状态,但不影响工作区的内容。这是默认的 reset 模式。
        • git reset --hard:移动 HEAD 指针,并将暂存区和工作区的内容都恢复到指定的提交状态,这将永久性地删除未提交的更改。
      • 假设当前分支在 commit-A,我们可以使用 git reset 命令将当前分支的指针移动到 commit-B 并且删除 commit-A 及其之后的提交记录,执行如下命令:
        git reset --hard commit-B
        
        上述命令会永久性地删除 commit-A 及其之后的提交记录,并将当前分支的指针移动到 commit-B
    • git reset 不同,git revert 命令不会删除提交记录,而是创建一个新的提交来撤销以前的提交。这种方法可以防止历史记录被删除,但也会在历史记录中添加一些不必要的提交。
      • 假设当前分支在 commit-A,我们可以使用 git revert 命令撤销 commit-A,执行如下命令:
        git revert commit-A
        
        上述命令会创建一个新的提交,将当前分支的内容恢复到撤销 commit-A 前的状态。

        需要注意的是,如果要撤销的提交不是当前分支的最新提交,git revert 命令可能会产生合并冲突,需要手动解决。