通过更新后Git头

时间:2014-09-12 20:30:16

标签: git githooks git-reset post-update

我有一个本地开发服务器,我会对其进行所有更改,我们将其称为local。 我在webserver的git文件夹中设置了git repo,我们称之为gitfolder。 然后我有我的实时文件,每当我推送时都会从gitfolder推送,我们称之为live

我的工作流程。

编辑文件,提交更改,推送到webserver。然后更新后接管以下内容:

#!/bin/sh
export GIT_WORK_TREE=/path/to/live
git checkout -f

这完美无缺。但是,这就是我的问题。我想恢复git更改,我通常会通过git reset --hard commit执行此操作 - 但如果我导航到live,那么显然这不是git repo。

当我转到gitfolder并运行相同的命令git reset --hard commit时,它不会更新live并且我得到错误'致命:此操作必须在工作树中运行“

采取的步骤?现在,我已经离开并复制了我的local文件夹并创建了local2 - 并在local2上我还原了更改,然后将其推送到live,所以我原来的local文件夹仍然包含所有更改。

我不想改回local - 只需live

1 个答案:

答案 0 :(得分:3)

你可能不想改变服务器中的任何引用(git reset会移动任何分支HEAD点,可能是master,但你说你不&# 39;我想恢复或重置您的本地系统,所以基于此,我假设您不想恢复或重置您的裸存储库。)

在这种情况下,只需登录服务器cd到裸存储库,然后运行:

git checkout --work-tree=/path/to/live checkout -f <commit-ID>

或:

GIT_WORK_TREE=/path/to/live git checkout -f <commit-ID>

换句话说,您只是执行更新挂钩所执行的操作,但使用原始提交ID来提取该特定版本,而不更改存储库本身中的任何分支。


虽然我认为这是您问题的字面答案,但我想指出一些其他内容:如果您git revert在您自己的本地存储库中进行了错误的提交,那么您会得到一个新的提交撤消错误提交的效果,但错误的提交仍在那里。然后,您可以按照通常的方式将结果推送到服务器:

... - o - X - o - U   <-- master, origin/master

其中X是错误的提交,而U是&#34; un-does&#34; X做了什么。仅仅是为了说明,我在他们之间也包含了一个无趣的o提交。

现在您可以简单地还原您的还原,以便您的本地回购结束于&#34;坏&#34;提交再次重播:

... - o - X - o - U       <-- origin/master
                    \
                      X'  <-- master

其中X'是错误提交的副本,其中&#34;取消&#34; U所做的撤消。您现在可以修复它,在顶部或git commit --amend等处进行另一次提交,当它完成后,再次git push将结果发送到服务器。这将是解决问题的更典型方式。


根据评论,这是另一个选项,可能适合也可能不适合,更好等:不是在本地重置或恢复,而是创建一个新的本地分支或标记(让我们在这里使用分支)要在服务器上恢复的提交。您可能还需要服务器上的名称,以便它不会进行垃圾收集提交(这意味着您将不得不在以后再次通过网络发送它们)。

例如,让我们说local上的树看起来像这样,用扭结绘制,以便我可以添加标签:

... - o - R
            \
              X - o - o -...- o   <-- HEAD=master, origin/master

此处R是您希望服务器重置的提交,而X和其他提交是更新Wordpress插件等的提交。 (我假设您正在分支master上工作;根据需要进行更改。)

同时,在服务器上,事情看起来像这样:

... - o - R
            \
              X - o - o -...- o   <-- HEAD=master

如果要保留服务器上的所有提交,我们应该为最终o提交一个新的分支名称,因为我们必须强制更新master。所以在local上,我们可以运行:

$ git push origin master:save

这将在服务器上创建一个名为save的新分支,现在看起来像这样:

... - o - R
            \
              X - o - o -...- o   <-- HEAD=master, save

update挂钩将执行通常的git checkout -f,它会检出HEAD分支(因为没有指定分支),在本例中为master,所以服务器更新到最后o提交(毫无意义,它已经存在)。但接下来,我们再次在local上执行此操作:

$ git branch for-server <commit-ID-for-R>

这会将local上的设置更改为如下所示:

... - o - R                       <-- for-server
            \
              X - o - o -...- o   <-- HEAD=master, origin/master

还不是很有趣,但接下来:

$ git push --force origin for-server:master

这个(带有--force)告诉服务器强行更新其master以指向提交R,之后它有:

... - o - R                       <-- HEAD=master
            \
              X - o - o -...- o   <-- save

save标签将剩余的提交保留在服务器上的存储库中。同时,post-update挂钩运行并执行git checkout -f,其使用HEAD,其指向master,其指向提交R。因此,Web服务器现在应该已部署提交R

回到local,您只需要记住for-server映射到遥控器上的master。 (如果您愿意,可以重命名所有本地分支以匹配服务器上的命名:例如,将master更改为save,然后将for-server更改为master。 #39; s全部独立于此。)

请注意,save唯一在服务器上执行的操作是保留提交X和所有后续o。如果您想直接在服务器上工作,或者不想通过网络发送这些提交,那就太好了。但是,如果在服务器(具有工作目录,因为它不是一个简单的回购),git checkout save,您将HEAD更改为指向{{ 1}}并且下次save挂钩运行时,它将部署post-update版本,而不是save版本。