Python log error存储_重置


  • 原文地址: CS Visualized: Useful Git Commands
  • 原文作者:Lydia Hallie

尽管Git是一个非常强力的工具,但如果我说这也可能是一场噩梦 ,我想大多数人也会同意。在使用Git的时候,我发现在我的大脑中想象发生了什么是非常有用的:在我执行特定命令的时候,分支之间是如何相互影响的,以及它会如何影响历史日志?当我在master分支做了硬重置(hard reset),强制推送(force push)到master分支并且rimraf .git目录之后,我的同事为什么会哭?

我认为为最常用和最有用的命令创建一些可视化的图例将会成为完美的使用示例! 我涉及到的许多命令拥有可选的参数,您可以使用这些参数来更改命令的行为。在示例中,我将会涉及没有添加(太多)配置项命令的默认行为!

Merging(合并)

拥有多个分支是极其方便的,他可以使新的更新彼此分离,也可以确保您不会意外的推送未经批准或破坏性更改的代码到生产环境。一旦更改被批准,我们便想在生产环境获得这些更改。

从一个分支获得另一个分支更改的一种方式是执行git merge命令。Git可以执行俩种类型的合并:

  1. fast-forward
  2. non-fast-forward

现在说这些可能没有太大意义,我们先看一下它们之间的区别。

Fast-forward(--ff)

与我们正在合并的分支相比,当当前分支没有额外提交的时候,会发生fast-forward-mergeGit是懒惰的,它会首先尝试最简单的选项:fast-forward!这种类型的合并不会创建一个新的提交,而是在当前分支上合并我们正在合并分支上的提交 。


Python log error存储_git_02


完美!我们现在在master分支上可以找到所有在dev分支上做出的更改。那么,non-fast-forward又是什么意思呢?

No-fast-forward(--no-ff)

相比于您想要合并的分支,当前分支没有任何额外的提交是极好的,但不幸的是那是很罕见的情况!如果在当前分支上提交的更改在我们想要合并的分支上不存在,Git将会执行一次no-fast-forward合并。

随着一次no-fast-forward合并,Git在活动分支(master)上创建一个新的合并提交。该提交的父提交同时指向活动分支和我们想要合并的分支(dev)。


Python log error存储_git_03


没什么大不了的,一次完美的合并! master分支现在包含了所有我们在dev分支上做出的所有更改。

Merge Conflicts(合并冲突)

尽管Git擅长如何去合并分支以及向文件中添加更改,但是它不能总是依靠它自己来做出所有的决定 。当我们尝试合并的俩个分支在同一个文件的同一行上有不同的更改,或者如果一个分支删除了一个在另一个分支被编辑过的文件等情况发生的时候,Git将不能自己决定该如何合并代码。

在这种情况下,Git将会询问您来帮助决定我们想要保留俩个选项中的哪一个。比如说在俩个分支上,我们都编辑了README.MD中的第一行。


Python log error存储_python“-o”命令更改存储位置_04


如果您想把dev合并到master,这将会导致合并冲突:您希望标题是Hello!还是Hey!?

在尝试合并分支的时候,Git将会为您显示冲突发生的位置。我们可以手动移除我们不想保留的更改,保存剩余的更改,再次添加文件到暂存区,然后提交所有更改的文件 。


Python log error存储_重置_05


好极了!尽管解决冲突十分烦人,但是它完全有意义:Git不应该只是假设我们想要保留哪些更改。

Rebasing

我们刚刚已经看过如何通过执行一个git merge命令,将来自于一个分支的更改应用到另一个分支。从一个分支添加更改到另一个分支的另一个方法是执行git rebase命令。

git rebase会从当前分支拷贝提交,并且将这些拷贝的提交放到指定分支的顶部。


Python log error存储_python“-o”命令更改存储位置_06


完美,我们现在在dev分支上可以找到所有在master分支上做出的更改!

rebasemerge命令一个最大的不同是:Git不会尝试去找出哪些文件要保留,哪些文件不需要保留。我们正在rebase的分支总是拥有我们想要保留的最新更改!这种方式在之后合并过程中不会遇到任何冲突,并且可以保持一个很好的直线Git历史记录。

“ 译者注:这里指的不会遇到任何冲突的情况如下(还是以上图为例):

  • dev$ git rebase masterdev的提交拷贝一份复制到master的顶部
  • dev$ git checkout master
  • master$ git merge dev 此时master相当于没有做任何额外的提交,会进行fast-forward-merge,保持直线提交记录

这个例子展示了在master分支上进行rebase。然而在更大的项目中,通常不希望这样做。由于拷贝的提交创建了新的哈希值,所以git rebase改变了项目的历史记录。

无论何时您在一个特性分支上工作,并且master分支已经被更新,rebase都是一种很好的做法。您可以在自己的分支上获取到所有的更新,这将阻止未来的合并冲突!

交互式的 rebase

rebase提交之前,我们可以编辑它们! 我们可以使用一个交互式的rebase来做这件事。交互式rebase对于您当前正在工作的分支以及想要修改的某些提交也是很有用处的。

在我们正在rebase的提交上有 6 个操作可以执行:

  • reword: 更改提交信息
  • edit: 修改这次提交
  • squash: 合并提交到之前的提交,会用新的提交信息覆盖之前的提交信息
  • fixup: 合并提交到之前的提交,不保留当前修改提交的日志消息
  • exec: 在我们想要rebase的每一个分支上运行一个命令
  • drop: 移除一个提交

棒极了!通过这种方式,我们可以完全控制在分支上做出的提交。如果我们想要移除一个提交,我们只需要对它执行drop命令。


Python log error存储_python“-o”命令更改存储位置_07


或者如果您想将多个提交压缩到一起来获得一个干净的历史记录,完全没有问题!


Python log error存储_重置_08


交互式rebase对于您正在尝试rebase的提交甚至是当前活动分支都给予了极大的控制权!

Resetting

这个命会在已经提交的更改在之后不想要的时候会被用到。可能它是一个还在工作进度中的半成品提交,或者可能提交引入了bug! 在这种情况,我们可以使用git reset命令。

git reset会删除当前暂存的所有文件,并且让我们控制HEAD应该指向的位置。

Soft reset

soft reset移动HEAD到指定的提交(或者提交相对于HEAD的索引),不会删除在提交之后引入的更改!

比如说我们不想保留添加了一个style.css文件的提交9478i,也不想保留添加了一个index.js文件的提交035cc。但是我们想要保留新添加的style.cssindex.js文件!这是soft reset一个完美的使用示例。


Python log error存储_数据_09


当输入git status时,您将会发现我们仍然可以访问在之前的提交做出的所有更改。这很好,因为这意味着我们可以继续处理这些文件,并且在之后再次提交它们!

Hard reset

有些时候,我们不想保留通过特定分支引入的更改。不同于soft reset,我们不再需要访问这些不想被保留的更改。Git应该只是重置它的状态回到指定提交的位置:被重置的状态甚至包括您在工作目录以及暂存文件中做出的更改!


Python log error存储_重置_10


Git已经丢弃了在9e78i035cc上引入的更改,并且重置它的状态到提交ec5be所在的位置

Reverting

撤销更改的另一个方式是执行git revert命令。通过恢复一个特定的提交,我们会创建一个包含被恢复更改的新提交!

比如说ec5be添加了一个index.js文件。之后,我们真正的意识到我们不再想要这次提交引入的更改!让我们恢复ec5be对应的提交。


Python log error存储_python“-o”命令更改存储位置_11


完美!提交9e78i恢复了ec5be提交引入的更改。在不修改分支历史的情况下,为了撤销一次特定的提交,执行git revert命令是特别有用的。

Cherry-picking

当一个特定分支中包含的一个提交,需要在我们的活动分支上引入它的更改时,我们可以使用cherry-pick命令!对一次提交进行cherry-pick,我们会在活动分支上创建一个新的提交,该提交会包含被cherry-pick的提交引入的更改。

比如说在dev分支上的提交76d12index.js文件添加了一个改动,我们在master分支上也想要拥有这次改动。我们不想要所有的提交,我们只关心这一个单独的提交!


Python log error存储_数据_12


很酷,master分支现在包含了76d12引入的更改!

Fetching

如果我们有一个远程Git分支,比如在GitHub上的一个分支,远程分支已经拥有了提交,但是当前分支却没有,这时会用到fetch命令!可能是另一个分支被合并到了远程分支,也可能是您的同事推送了一个快速修复等等情况。

通过在远程分支上执行git fetch命令,我们可以在本地获得这些更改!它不会以任何方式影响您的本地分支:fetch只是下载了新的数据。


Python log error存储_重置_13


现在我们可以看到从最后一次推送之后做出的所有更改!现在我们在本地拥有了新数据,我们可以决定想要用新数据做什么。

Pulling

尽管为了获取一个分支的远程信息,git fetch是及其有用的,但是我们也可以执行git pull命令。git pull实际上是将俩个命令合为了一个命令:git fetch + git merge。当我们从origin分支拉取更改的时候,首先会像执行git fetch命令一样fetch所有的数据,在这之后自动地将最新的更改合并到本地分支。


Python log error存储_python“-o”命令更改存储位置_14


太好了,我们现在完美的同步了远程分支的数据,并且拥有了所有最新的更改!

Reflog

每个人都会犯错,这完全可以理解!有些时候您可能会感觉已经搞砸了您的Git仓库,以至于您特别想整个删掉它。

git reflog是一个非常有用的命令,目的是用来显示已经被采取的所有操作的日志!日志中包括merge,reset,rervert:基本上会显示任何对您分支做出更改的操作日志。


Python log error存储_python“-o”命令更改存储位置_15


如果您不小心犯了一个错误,您可以轻易的基于reflog给我们提供的信息重置HEAD到之前的位置,然后重做我们之前做错的事情!

比如说实际上我们不想合并origin分支。当我们执行git reflog命令时,将会看到在合并之前仓库的状态是在HEAD@{1}。让我们执行git resetHEAD指回到HEAD@{1}的位置!


Python log error存储_数据_16


我们可以看到最新的操作已经被推到了reflog中!

译者注:
到这里文章就结束了,笔者通过思维导图整理了一下对应的知识点,希望能对阅读文章的小伙伴有所帮助


Python log error存储_git_17