【问题标题】:How do I force pull when I can't get rid of local changes AND without losing local commits?当我无法摆脱本地更改并且不丢失本地提交时,如何强制拉取?
【发布时间】:2014-03-31 10:35:24
【问题描述】:

我遇到以下情况:同事提交了一堆带有 Windows 行结尾的文件。我们有一个.gitattribute,它在commit 期间删除了Windows 行尾。

这意味着在pull 之后,我有几十个文件被标记为“本地更改”,而实际上它们没有。我无法检查它们,因为 Git 会将(损坏的)文件从存储库中取出(它具有 Windows 行结尾),修复行结尾以最终得到一个始终与当前存储库中的文件不同的文件。

团队的一名成员已修复这些文件并提交并推送它们。

这个问题以丢失所有本地提交(即尚未推送的所有内容)为代价回答了我的问题:How do I force "git pull" to overwrite local files?

如何在不丢失本地提交的情况下拉取

这是我在服务器上的 Git 存储库:

A --> B --> BAD1 --> FIX1(HEAD)

BAD1 包含错误提交,FIX1 修复它们。

这是我目前磁盘上的内容:

A --> B --> BAD1 --> LC1 --> LC2(HEAD)
              \---> FIX1

我是通过git pull --rebase 到达这里的。在那个命令之前,我有:

A --> B --> LC1 --> LC2(HEAD)

我想结束的是:

A --> B --> BAD1 --> FIX1 --> LC1 --> LC2(HEAD)

【问题讨论】:

  • .gitattributes 不会删除 Windows 行尾在拉取和结帐时,它会删除它们在提交。根据您的设置,Windows 行尾仅在结帐时恢复
  • @Cupcake:啊啊啊啊……现在,这种行为开始变得(更)有意义了。出于某种原因,提交包含 Windows 行结尾,我通过 pull/checkout 得到它们。 Git 如何在diffstatus 期间注意到这样的文件不同? diff 是否也应用这些属性?

标签: git git-merge git-pull


【解决方案1】:

您链接到的答案与您需要做的类似。由于您的其他同事已经修复了行尾并推送了更改,您只需 fetch 来自原点的新更改,然后 merge 将它们放入您的本地工作中,或者 rebase 您的本地工作在它们之上:

git fetch <remote>
git checkout <local-branch>

# Merge changes
git merge <remote>/<remote-branch>

# Or rebase
git rebase <remote>/<remote-branch>

fetch 永远不会覆盖您本地分支上的工作,它所做的只是更新您的远程跟踪分支。实际上,pull 只是一个 fetch 后跟一个 merge

更新

由于您的工作副本已修改文件(仅因为行结尾),我想这会阻止您重新定位。所以你可以简单地清理你的工作副本,硬重置回到之前的良好状态,合并到固定的提交中,然后将你的本地提交重新挑选出来(使用它们的 sha ID)。

将所有内容放在一起,它看起来像这样:

git checkout -- .
git reset --hard B
git merge <remote> <branch>
git cherry-pick LC1 LC2

当您进行硬重置时,git 不会立即删除您的任何提交。 Git 将所有无法从分支或引用访问的提交保留一段时间(默认为 2 周),然后最终从 repo 垃圾收集它们。您可以通过运行 git gc 来启动早期垃圾收集,但显然您现在不想这样做。

因为实际上并没有立即删除任何提交,所以您仍然可以使用它们的 sha ID 来引用它们,这就是为什么您可以在合并到固定提交后将它们重新挑选到您的分支顶部。

【讨论】:

  • 如果本地结帐已经拉出错误提交(即local-branch 造成上述情况),我该如何修复?
  • 一种选择是 git reset --hard 摆脱错误提交,然后 mergerebase,但如果您已经在错误提交之上完成了本地工作,那么您要么只需要merge 并修复冲突,要么你可以进行硬重置,合并好的提交,然后将你的旧工作重新挑选出来(这与交互式rebase 基本相同)。您是否可以展示来自git log --graph --oneline 的相关提交是什么样的?
  • git clean不一样。 Git 的checkout 命令也用于恢复对工作副本的更改,所以git checkout -- . 的意思是“在此路径中恢复对我的工作副本的所有更改”,传递的路径是当前目录.。另一方面,git clean 用于删除尚未跟踪/添加到您的 git 存储库历史记录中的文件。
  • 这样想,您可以通过再次“检查”文件的历史状态来恢复对文件的修改,从而“覆盖”本地修改。您可以将git checkout -- &lt;path&gt; 视为git checkout HEAD -- &lt;path&gt; 的简写。您甚至可以从不同的分支或修订/提交中签出特定文件的不同版本,例如 git checkout &lt;branch&gt; -- &lt;path&gt;git checkout &lt;commit-sha&gt; -- &lt;path&gt;
  • reset --hard 表示您将分支从地下拉出,并随身携带到 B 提交,然后将其直接放在它旁边。我的即兴类比有意义吗?我也喜欢使用另一个类比,“附有便利贴的提交树”,便利贴代表分支引用。您可以拿起便利贴并使用git reset 移动它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多