如何重置master并将我的分支保留在git中?

时间:2017-03-28 20:02:58

标签: git git-reset

假设我

$ git checkout master
$ touch foo.py
$ git commit -m "oops" foo.py
$ git checkout -b new_branch
$ touch bar.py
$ git commit -m "changes" bar.py

现在当我尝试推回new_branch上的更改时,我得到了

Local branch 'master' is ahead of remote branch 'origin/master'

如何在new_branch上不丢失我的更改(foo.py,bar.py)的同时重置master?

我读了git reset page,看起来可能涉及 - 保持,但我不知道。

2 个答案:

答案 0 :(得分:4)

最初这可能非常混乱,你需要的是对Git如何实现分支的正确介绍;但此时我们将使用改造方法。 :-)理解这一切的诀窍是,Git的提交是永久性的,不变的,但它的分支 - 或者更确切地说,分支名称< / em> - 暂时的,实际上大部分是不相关的。

构建提交时,有三件事情很重要(它们是HEAD索引工作树),但是一旦你建立并提交了提交,它就会非常永久,而且很难让Git完全失去它。不过,它很容易被误放,所以让我们试着避免这种情况。 : - )

如果我们完全忽略分支名称,我们可以绘制存储库中存在的提交的图形。鉴于你做了两件事 - 做了两次新的提交 - 让我们像这样绘制它们,其中圆o代表提交,AB是你的两个新的提交:

...--o--o--o
            \
             A
              \
               B

我们可以在一条线上绘制它们,但我想留出空间在右边写标签。提交A是您的&#34; oops&#34;,B是您的更改&#34;。

关于此图形绘制的主要值得注意的事情是每个提交指向(存储其前缀提交的哈希ID)。这意味着提交B指向提交A。将A提交回到下一个最近提交的提交,指向更进一步,等等。

现在我们添加标签 - 分支名称。最后一个无聊的提交o仍然可能有一个标签origin/master。提交A的标签为master,提交B的标签为new_branch,因此请在以下位置提取:

...--o--o--o   <-- origin/master
            \
             A   <-- master
              \
               B   <-- new_branch (HEAD)

这是分支名称为您做的事情:它们是提交的指针;他们会为你记住每个提交的大丑哈希ID。

当您在某个分支上并进行提交时,分支名称随之而来。特殊名称HEAD会记住您所在的分支,以便Git知道将移动的名称添加到新提交中。 (我们至少暂时需要这个,当masternew_branch短暂指向提交A时。)

您现在要做的是将master 移回以指向最后一个无聊的o提交。为此,您可以使用git reset,以便以任意方式移动名称:

git checkout master
git reset --hard origin/master

假定(请参阅下面的最后一部分)origin/master确实 指向最后一个无聊的o提交。 git reset --hard说:擦除我当前的索引和工作树,并根据HEAD移动我当前的分支 - 以便它指向我在这里命名的提交。我们必须git checkout master 首先,以便HEAD名称为master。然后git reset执行此操作:

...--o--o--o   <-- master (HEAD), origin/master
            \
             A
              \
               B   <-- new_branch

现在,您的两个新提交AB只能通过new_branch而不是master找到。

(分支名称还有其他一些功能。特别是,他们保护提交被Git&#34;#34;垃圾收集器&#34;删除。 commit有我们可以找到它的任何名称,它受到保护。如果它有 no 名称,它就不再受到保护。有一些半隐藏名称可以保护所有内容一段时间 - 默认情况下至少30天 - 确保提交不会意外发生,但通过这些 reflog 名称找到它们很烦人,所以我们尽量不依赖它得多。

分支名称也用于git push,因此它们很重要。)

(我提及&#34;垃圾&#34;上面的索引和工作树,这不完全正确。git reset命令,使用我们在这里使用它的方式,它有三项工作可以做:

  • 移动当前分支
  • 重置索引
  • 重置工作树

它始终执行第一个,可选地添加第二个作业,然后可选地添加第三个​​作业。 --hard模式完成所有三个模式,--mixed模式执行前两个模式,--soft模式只执行一个模式。要正确理解它们,我们必须仔细查看 index work-tree 的定义,并将其留给其他SO问题/答案。但是,这里的关键项目是, 想要git reset --hard,直到您在提交中保存了所有内容。)

如果没有origin/master(或者它指向太远)怎么办?

我们上面假设有一个方便的标签 - 一个所谓的远程跟踪分支 - 识别我们希望git reset master我们git log指向的提交-至。如果我们没有这个标签,或者它指向更早的提交,我们必须以其他方式找到该提交。

有很多方法可以做到这一点。最简单的方法是使用其哈希ID。如果您在某个分支上运行git log,则会看到每个提交都是&#34; on&#34;或&#34;包含在&#34;那个分支,通常是Git常用的后退顺序。例如,我们可能会B看到提交A,其丑陋的哈希ID,然后使用其哈希ID提交o,然后使用其无聊的提交git checkout master && git reset --hard <hash-id> 丑陋的哈希ID。

我们可以使用原始哈希ID:

git log

如果我们没有标签。如果我们有标签,我们应该只使用它。

你可能还记得从#34; A DOG&#34;与git log --all --decorate --oneline --graph

{{1}}

a ll使Git显示所有分支和所有远程跟踪分支(以及其他所有内容:标记,&#34; stash&#34;,注释等)。 d ecorate选项将标签名称附加到提交。 o neline选项使输出每次提交只显示一行, g raph选项使Git尝试绘制提交图。

答案 1 :(得分:0)

如何在new_branch上不丢失我的更改(foo.py,bar.py)的同时重置master?

  

是的,foo.py和bar.py在您的新分支中。

  • 您已从主人创建了一个未被推送到原点的分支。所以当你试图推动主人时你会得到错误,因为它超前了。

  • 您收到该消息是因为您在本地主服务器中进行了更改,而您没有将它们推送到远程服务器。

您有多种方法可以“解决”它,通常取决于您的工作流程:

  • 在良好的工作流程中,您的远程主副本应该是好的,而您的本地主副本只是远程主副本的副本。使用此工作流程,您将永远不会再收到此消息。

  • 如果您以其他方式工作并且应该推送您的本地更改,那么只需git push origin,假设origin是您的远程

我将如何做到这一点:

git checkout master
git create -b la_lalalla
touch foo.py bar.py
git add drama.py bar.py
git commit -m "Drama commit"

将分支合并到您的主服务器,这取决于您进行合并或进行rebase,然后,

git push origin master. 

完成了将两个文件添加到origin / master。