假设我
$ 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,看起来可能涉及 - 保持,但我不知道。
答案 0 :(得分:4)
最初这可能非常混乱,你需要的是对Git如何实现分支的正确介绍;但此时我们将使用改造方法。 :-)理解这一切的诀窍是,Git的提交是永久性的,不变的,但它的分支 - 或者更确切地说,分支名称< / em> - 暂时的,实际上大部分是不相关的。
构建新提交时,有三件事情很重要(它们是HEAD
,索引和工作树),但是一旦你建立并提交了提交,它就会非常永久,而且很难让Git完全失去它。不过,它很容易被误放,所以让我们试着避免这种情况。 : - )
如果我们完全忽略分支名称,我们可以绘制存储库中存在的提交的图形。鉴于你做了两件事 - 做了两次新的提交 - 让我们像这样绘制它们,其中圆o
代表提交,A
和B
是你的两个新的提交:
...--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知道将移动的名称添加到新提交中。 (我们至少暂时需要这个,当master
和new_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
现在,您的两个新提交A
和B
只能通过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。