如何强制“git pull”覆盖本地文件?

git version-control overwrite git-pull git-fetch

如何强制覆盖 git pull 上的本地文件?我的本地存储库包含一个文件名与服务器上相同的文件。

错误:未跟踪的工作树文件“example.txt”将被合并覆盖

任何阅读此书的人认为他们可能会丢失文件,我一直处于这个位置,发现 Sublime Text 的缓冲区救了我 - 如果我正在处理某些事情,然后通过尝试解决与此类似的问题或使用来意外删除所有内容对此问题的答案并已在 Sublime 中打开文件(很有可能),那么文件仍将存在 Sublime,要么就在那里,要么在撤消历史记录中

git reset --hard origin/branch_to_overwrite

基本上,只在初始结帐-b 之后从开发中拉取。做你的工作,然后推回去。

简短的回答:删除并重新创建分支。 1. 删除分支:git branch <branch> -D 2. 重置为冲突前的提交:git reset <commit> --hard 3. 重新创建分支:git branch <branch> 4. 设置对服务器的跟踪:git --set-upstream-to=origin/<branch> <branch> 5. Pull: git pull`

要将所有 CRLF 更改为 LF 结尾,(start clean)git config core.autocrlf false; git ls-files -z | xargs -0 rm; git checkout .

T
Top-Master

⚠ 重要提示:如果您有任何本地更改,它们将会丢失(如果它们被跟踪)。此外,无论是否使用 --hard 选项,任何未推送的本地提交都将丢失。[*]

如果您有任何 Git 未跟踪的文件(例如上传的用户内容),这些文件不会受到影响。

首先,运行 fetch 以将所有 origin/<branch> 引用更新为最新:

git fetch --all

备份当前分支:

git branch backup-master

然后,您有两个选择:

git reset --hard origin/master

或者,如果您在其他分支上:

git reset --hard origin/<branch_name>

解释:

git fetch 从远程下载最新版本,而不尝试合并或变基任何内容。

然后 git reset 将主分支重置为您刚刚获取的内容。 --hard 选项更改工作树中的所有文件以匹配 origin/master 中的文件

维护当前的本地提交

[*]:值得注意的是,可以通过在重置之前从 master 创建一个分支来维护当前的本地提交:

git checkout master
git branch new-branch-to-save-current-commits
git fetch --all
git reset --hard origin/master

在此之后,所有旧的提交都将保存在 new-branch-to-save-current-commits 中。

未提交的更改

然而,未提交的更改(即使是分阶段的)将会丢失。确保存储并提交您需要的任何内容。为此,您可以运行以下命令:

git stash

然后重新应用这些未提交的更改:

git stash pop

小心!如果您有本地未推送的提交,这会将它们从您的分支中删除!此解决方案使存储库中未跟踪的文件保持完整,但会覆盖其他所有内容。

这是一个受欢迎的问题,所以我想澄清一下这里的顶级评论。我只是按照这个答案中的描述执行了命令,并没有删除所有本地文件。只有远程跟踪的文件被覆盖,而这里的每个本地文件都保持不变。

如果您从远程分支名称不同于“master”的 repo 中提取,请使用 git reset --hard origin/branch-name

鉴于对这个问题和答案的赞成票数量,我认为 git 应该包含像 git pull -f 这样的命令

可以使用 git reflog 恢复在硬重置之前未推送的提交,其中列出了所有提交,也包括那些没有基础的提交。在您使用 git gc 清理本地副本之前,一切都会丢失

P
Peter Mortensen

尝试这个:

git reset --hard HEAD
git pull

它应该做你想做的事。

我已经这样做了,并且一些不再在 repo 中的本地文件留在了磁盘上。

我不认为这是正确的。以上将执行合并,而不是覆盖问题中要求的:“如何强制 git 覆盖它们?”我没有答案,我目前正在寻找它.. 目前我使用要保留的代码切换到分支“git checkout BranchWithCodeToKeep”,然后执行“git branch -D BranchToOverwrite”,最后“git checkout -b BranchToOverwrite”。您现在将在分支 BranchToOverwrite 上获得来自 BranchWithCodeToKeep 的确切代码,而无需执行合并。

而不是使用 'git pull' 合并,尝试 git fetch --all 后跟 'git reset --hard origin/master'

是的,@lloydmoore 解决方案对我有用。可以做一个答案,而不仅仅是一个评论。

这会将当前更改重置为最后一个分支提交。然后 git pull 合并来自最新分支的更改。这正是我想要它做的......谢谢!

D
David Avsajanishvili

警告:git clean 会删除您所有未跟踪的文件/目录且无法撤消。

有时只是 clean -f 无济于事。如果您有未跟踪的目录,还需要 -d 选项:

# WARNING: this can't be undone!

git reset --hard HEAD
git clean -f -d
git pull

警告:git clean 会删除您所有未跟踪的文件/目录且无法撤消。

考虑首先使用 -n (--dry-run) 标志。这将向您显示将被删除的内容而不实际删除任何内容:

git clean -n -f -d

示例输出:

Would remove untracked-file-1.txt
Would remove untracked-file-2.txt
Would remove untracked/folder
...

您可以为 git clean 提供更具体的路径参数,并避免删除不冲突的未跟踪文件。

我认为场景描述清楚地表明他并不想丢弃内容。相反,他想要的是停止 git 在覆盖文件时犹豫不决。 @Lauri,这不应该发生在你身上。不幸的是,人们似乎误读了场景描述的本质——请参阅我的建议。

最后。当 make clean 无法清理所有内容时, git clean -f -d 很方便。

@crizCraig 除非它们被添加到 .gitignore

@earthmeLon,为此您可能需要 git clean -dfx-x 忽略 .gitignore。通常,您的构建产品将位于 .gitignore 中。

T
TheTechRobo Stands for Ukraine

像刺猬一样,我认为答案很糟糕。但是尽管刺猬的回答可能会更好,但我认为它并没有它可以的那么优雅。我发现这样做的方法是使用带有定义策略的 fetchmerge。只要它们不是您尝试强制覆盖的文件之一,就应该这样做,以便保留您的本地更改。

首先提交您的更改

 git add *
 git commit -a -m "local file server commit message"

然后获取更改并在有冲突时覆盖

 git fetch origin master
 git merge -s recursive -X theirs origin/master

-X 是选项名称,theirs 是该选项的值。如果存在冲突,您选择使用 their 更改(另一个选项是 ours 更改)。

这是迄今为止我看到的最好的答案。我没有尝试过,但与其他答案不同,这不会尝试对所有未跟踪的文件进行核对,这很危险,原因很明显。

同上 - 这对我进行非常大的合并(GitHub 拉取请求)时对我有用,我只是想在我所拥有的基础上接受它。好答案!在我的例子中,最后两个命令是:1) get fetch other-repo; 2) git merge -s recursive -X theirs other-repo/master

这将覆盖与存储库文件而不是本地文件的任何冲突,对吗?

最佳答案。在我的案例中,接受度最高的答案让我心不在焉。我切换回本地主分支并运行 git merge -X theirs origin/master

我只是想让该死的 git 覆盖所有内容并闭嘴。毕竟我只是在我的工作电脑和一些树莓派系统之间使用它。渴望强制覆盖选项,至少对于项目负责人

J
Johanneke

而不是这样做:

git fetch --all
git reset --hard origin/master

我建议执行以下操作:

git fetch origin master
git reset --hard origin/master

如果您要重置到原始/主分支,则无需获取所有遥控器和分支,对吗?

您的答案正是您的代表所需要的。我必须问,这是否也会删除所有未跟踪的文件?

是的,我的大部分代表都来自这里 :) 这也将删除所有未跟踪的文件。就在两天前,我忘记并痛苦地想起了一些事情……

请参阅对此其他答案的评论:stackoverflow.com/a/8888015/2151700

这并没有删除我未跟踪的文件;这实际上是我所期望的。是否有理由对某些人而不是对其他人?

这正是我所需要的:覆盖远程中存在的未跟踪文件,并使其他所有内容保持不变。

P
Peter Mortensen

看起来最好的方法是先做:

git clean

要删除所有未跟踪的文件,然后继续使用通常的 git pull...

我尝试使用“git clean”来解决同样的问题,但没有解决。 git status 说“你的分支和'origin/master'已经分道扬镳,分别有 2 和 9 个不同的提交。”和 git pull 说的话类似于你上面所说的。

git clean 是一个相当生硬的工具,可能会丢弃很多你可能想要保留的东西。最好删除或重命名 git 抱怨的文件,直到拉取成功。

我认为这在一般情况下是行不通的。有没有办法通过强制 git pull 基本上完成 git clone 远程操作?

@mathick:git fetch origin && git reset --hard origin/master

git clean 是最佳答案吗?似乎删除文件不一定是 OP 想要的。他们要求“覆盖本地文件”而不是删除。

H
Hedgehog

Warning, doing this will permanently delete your files if you have any directory/* entries in your gitignore file.

有些答案似乎很糟糕。通过遵循 David Avsajanishvili 的建议,@Lauri 发生的事情很糟糕。

而是(git > v1.7.6):

git stash --include-untracked
git pull

稍后您可以清理存储历史记录。

手动,一个一个:

$ git stash list
stash@{0}: WIP on <branch>: ...
stash@{1}: WIP on <branch>: ...

$ git stash drop stash@{0}
$ git stash drop stash@{1}

残酷地,一次性:

$ git stash clear

当然,如果你想回到你隐藏的东西:

$ git stash list
...
$ git stash apply stash@{5}

不,我不这么认为。存储只是将未提交的文件移开。上面还移动(隐藏)git 不跟踪的文件。这可以防止已添加到远程的文件被拉下,这些文件还没有拉到你的机器上——但是你已经创建了(!)——被拉下。所有这些都不会破坏未提交的工作。希望这有意义吗?

如果您没有 1.7.6,您可以通过临时 git add-ing 整个存储库来模仿 --include-untracked,然后立即隐藏它。

我同意刺猬的观点。如果你在这里做流行的答案,你很可能会发现你无意中杀死了很多你不想失去的东西。

我还有其他未跟踪的文件——除了合并/拉取想要覆盖的文件,所以这个解决方案效果最好。 git stash apply 带回了我所有未跟踪的文件,但(正确地)合并已创建的文件除外:“已经存在,不签出。”工作完美。

这是最干净的答案,应该是公认的答案。要节省一些输入,您可以使用缩写形式:git stash -u

P
Peter Mortensen

您可能会发现此命令有助于丢弃本地更改:

git checkout <your-branch> -f

然后进行清理(从工作树中删除未跟踪的文件):

git clean -f

如果要删除除未跟踪文件之外的未跟踪目录:

git clean -fd

我认为场景描述清楚地表明他并不想丢弃内容。相反,他想要的是停止 git 在覆盖文件时犹豫不决。看我的建议。

尽管该答案可能不完全符合描述,但它仍然使我免于 git 玩弄回车的挫败感(autocrlf 为 false 的事件)。当 git reset --hard HEAD 不会给您留下“没有”修改过的文件时,这些“-f”标志非常有用。谢谢一堆。

s
sbarb

不要与 git pull 合并,试试这个:

git fetch --all

其次是:

git reset --hard origin/master

这在脚本中不起作用,因为您必须知道分支名称。以通用方式查看我的解决方案

C
Community

唯一对我有用的是:

git reset --hard HEAD~5

这将使您返回五个提交,然后

git pull

我通过查找 how to undo a Git merge 发现了这一点。

这最终对我有用,因为我强制将我的分支推送到原始存储库,并在尝试将其拉到我的远程存储库时不断遇到合并冲突。

嗨,实际上这是 work around 的一个技巧,但非常有效。因为一些冲突可能只发生在几次提交中,所以恢复 5 次提交将确保与远程代码没有冲突。

V
Vlad L.

所有这些解决方案的问题是它们要么太复杂,要么更大的问题是它们从网络服务器中删除了所有未跟踪的文件,这是我们不想要的,因为服务器上总是需要配置文件而不是在 Git 存储库中。

这是我们使用的最干净的解决方案:

# Fetch the newest code
git fetch

# Delete all files which are being added, so there
# are no conflicts with untracked files
for file in `git diff HEAD..origin/master --name-status | awk '/^A/ {print $2}'`
do
    rm -f -- "$file"
done

# Checkout all files which were locally modified
for file in `git diff --name-status | awk '/^[CDMRTUX]/ {print $2}'`
do
    git checkout -- "$file"
done

# Finally pull all the changes
# (you could merge as well e.g. 'merge origin/master')
git pull

第一个命令获取最新数据。

第二个命令检查是否有任何文件正在添加到存储库中,并从本地存储库中删除那些会导致冲突的未跟踪文件。

第三个命令检出所有在本地修改的文件。

最后,我们拉取更新到最新版本,但这次没有任何冲突,因为仓库中未跟踪的文件不再存在,并且所有本地修改的文件已经与仓库中的相同。

使用“git merge origin/master”作为最后一行(就像你在笔记中所说的那样)而不是“git pull”会更快,因为你已经从 git repo 中删除了任何更改。

是的,当然,git merge origin/master 会更快,甚至可能更安全。因为如果有人在删除此脚本的文件期间推送了新的更改(这不太可能发生,但可能发生),整个拉取可能会失败。我把 pull 放在那里的唯一原因是因为有人可能不在 master 分支上工作,而是在其他一些分支上工作,我希望脚本是通用的。

如果您有本地创建的文件(如选项文件),请将它们放在 .gitignore 中。

k
kenorb

首先,尝试标准方式:

git reset HEAD --hard # To remove all not committed changes!
git clean -fd         # To remove all untracked (non-git) files and folders!

警告:仅当您没有提交上述命令时,它们才会导致数据/文件丢失!如果您不确定,请先备份整个存储库文件夹。

然后再拉一次。

如果上述方法没有帮助并且您不关心未跟踪的文件/目录(以防万一,请先进行备份),请尝试以下简单步骤:

cd your_git_repo  # where 'your_git_repo' is your git repository folder
rm -rfv *         # WARNING: only run inside your git repository!
git pull          # pull the sources again

这将删除所有 git 文件(除了 .git/ 目录,您有所有提交)并再次拉取它。

为什么 git reset HEAD --hard 在某些情况下会失败?

.gitattributes 文件中的自定义规则 .gitattributes 中的 eol=lf 规则可能会导致 git 通过将 CRLF 行尾转换为某些文本文件中的 LF 来修改某些文件更改。如果是这种情况,您必须提交这些 CRLF/LF 更改(通过在 git status 中查看它们),或者尝试: git config core.autcrlf false 暂时忽略它们。文件系统不兼容当您使用不支持权限属性的文件系统时。例如,您有两个存储库,一个在 Linux/Mac (ext3/hfs+) 上,另一个在基于 FAT32/NTFS 的文件系统上。正如您所注意到的,有两种不同的文件系统,因此不支持 Unix 权限的文件系统基本上无法在不支持这种权限的系统上重置文件权限,所以无论如何 --hard 你试试看,git 总是会检测到一些“变化”。

S
SherylHohman

我有同样的问题。没有人给我这个解决方案,但它对我有用。

我通过以下方式解决了它:

删除所有文件。只留下 .git 目录。 git reset --hard HEAD git pull git push

现在它起作用了。

同样在这里。有时只有非常困难的解决方案才能奏效,经常发生仅重置和清理是不够的......

C
Community

奖金:

在谈到之前答案中的拉/取/合并时,我想分享一个有趣且富有成效的技巧,

git pull --rebase

上面这个命令是我 Git 生活中最有用的命令,它节省了很多时间。

在将您的新提交推送到服务器之前,请尝试使用此命令,它会自动同步最新的服务器更改(使用 fetch + 合并)并将您的提交放在 Git 日志的顶部。无需担心手动拉/合并。

What does "git pull --rebase" do? 中查找详细信息。

简而言之:git pull -r

就我而言,在这样做之前,我必须 1) git add -A、2) git commit -m 3) 最后是 git pull rebase。谢谢你。

w
warch

如果您不总是想粘贴分支名称或者您想在脚本中自动执行此操作,这是一个通用解决方案

git fetch
git reset --keep origin/$(git rev-parse --abbrev-ref HEAD)

如果您也想重置本地更改:

git fetch
git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)

您还可以使用以下命令添加 bash 别名:

alias gplf='git fetch && echo "HEAD was at $(git rev-parse --short HEAD)" && git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)'

如果您发现自己经常使用它,请添加一个 bash 快捷方式 alias gplf='git fetch && echo "HEAD was at $(git rev-parse --short HEAD)" && git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)'

杰出的。谢谢!人们在回答时不考虑自动脚本。当您无法传递分支名称时,这非常优雅。

这个中间的对我有用:git fetch 其次是 git reset --hard origin/$(git rev-parse --abbrev-ref HEAD)。我选择它是因为它的简单性和答案的最新性。

A
Alexsander Akers

我有一个类似的问题。我不得不这样做:

git reset --hard HEAD
git clean -f
git pull

谨慎使用 git clean

P
Peter Mortensen

我总结了其他答案。您可以执行 git pull 而不会出错:

git fetch --all
git reset --hard origin/master
git reset --hard HEAD
git clean -f -d
git pull

警告:此脚本非常强大,因此您可能会丢失所做的更改。

这将覆盖修改过的文件(之前签入的文件),并将删除未跟踪的文件(从未签入的文件)。正是我要找的,谢谢!

我怀疑第三行 git reset --hard HEAD 可能是多余的;我的本地手册页 (2.6.3) 在第二行中说 reset git reset --hard origin/master “在所有形式中都默认为 HEAD。”

@arichards 我认为您的嫌疑人是对的,但是如果第二行不起作用(出于任何原因),第三行可以很好地重置。此解决方案不需要优化。我只是总结了其他答案。就这样。感谢您的评论。 :)

谢谢你的总结。这些步骤确实很强大:)

N
Nathaniel Ford

根据我自己的类似经验,上面 Strahinja Kustudic 提供的解决方案是迄今为止最好的。正如其他人指出的那样,简单地进行硬重置将删除所有未跟踪的文件,其中可能包含许多您不想删除的内容,例如配置文件。更安全的是,只删除即将添加的文件,就此而言,您可能还希望签出任何即将更新的本地修改文件。

考虑到这一点,我更新了 Kustudic 的脚本来做到这一点。我还修正了一个错字(原文中缺少 ')。

#/bin/sh

# Fetch the newest code
git fetch

# Delete all files which are being added,
# so there are no conflicts with untracked files
for file in `git diff HEAD..origin/master --name-status | awk '/^A/ {print $2}'`
do
    echo "Deleting untracked file $file..."
    rm -vf "$file"
done

# Checkout all files which have been locally modified
for file in `git diff HEAD..origin/master --name-status | awk '/^M/ {print $2}'`
do
    echo "Checking out modified file $file..."
    git checkout $file
done

# Finally merge all the changes (you could use merge here as well)
git pull

使用“git merge origin/master”作为最后一行(就像你在笔记中所说的那样)而不是“git pull”会更快,因为你已经从 git repo 中删除了任何更改。

需要签出修改过的文件,所以这可以 100% 工作。我很久以前就用它更新了我的脚本,但也忘了在这里更新。我的使用方式也与您有所不同。我检查具有任何类型修改的文件,而不仅仅是 M,所以它一直有效。

P
Peter Mortensen

我遇到了同样的问题,出于某种原因,即使是 git clean -f -d 也不会这样做。原因如下:由于某种原因,如果 Git 忽略了您的文件(我假设是通过 .gitignore 条目),它仍然会为稍后的 pull 覆盖它而烦恼,但是 clean 不会删除它,除非您添加 -x

t
tiho

我相信有两种可能的冲突原因,必须单独解决,据我所知,上述答案都没有涉及:

需要手动删除未跟踪的本地文件(更安全)或按照其他答案中的建议,通过 git clean -f -d

不在远程分支上的本地提交也需要删除。 IMO 实现这一目标的最简单方法是: git reset --hard origin/master (用您正在处理的任何分支替换“master”,然后首先运行 git fetch origin)

C
Community

似乎这里的大多数答案都集中在 master 分支上;但是,有时我在两个不同的地方处理同一个特性分支,我希望一个 rebase 能够反映在另一个地方,而不需要太多的跳跃。

基于 RNA's answertorek's answer to a similar question 的组合,我想出了这个非常有效的方法:

git fetch
git reset --hard @{u}

从分支运行它,它只会将您的本地分支重置为上游版本。

这也可以很好地放入 git 别名 (git forcepull) 中:

git config alias.forcepull "!git fetch ; git reset --hard @{u}"

或者,在您的 .gitconfig 文件中:

[alias]
  forcepull = "!git fetch ; git reset --hard @{u}"

享受!

这个答案也很好,因为无论您在哪个分支上,它都可以工作!

m
maximus 69

一种更简单的方法是:

git checkout --theirs /path/to/file.extension
git pull origin master

这将使用 git 上的文件覆盖您的本地文件

P
Peter Mortensen

我自己解决了这个问题:

git checkout -b tmp # "tmp" or pick a better name for your local changes branch
git add -A
git commit -m 'tmp'
git pull
git checkout master # Or whatever branch you were on originally
git pull
git diff tmp

最后一个命令列出了您的本地更改的列表。继续修改“tmp”分支,直到它可以接受,然后合并回master:

git checkout master && git merge tmp

下次,您可能可以通过查找“git stash branch”以更简洁的方式处理此问题,尽管 stash 可能会在前几次尝试中给您带来麻烦,因此请先在非关键项目上进行实验......

J
Jacob Gunther

我有一个奇怪的情况,git cleangit reset 都不起作用。我必须通过对每个未跟踪文件使用以下脚本从 git index 中删除冲突文件:

git rm [file]

然后我就可以拉得很好了。

R
Ricky McMaster

我知道一种更容易且痛苦更少的方法:

$ git branch -m [branch_to_force_pull] tmp
$ git fetch
$ git checkout [branch_to_force_pull]
$ git branch -D tmp

而已!

我尝试按照此答案中的建议进行操作。根本没有从远程存储库中提取任何文件。仔细想想其实并不奇怪 - 毕竟根本没有提到 origin/<branch_to_force_pull>

P
Peter Mortensen

要求:

跟踪本地更改,因此这里没有人会丢失它们。使本地存储库与远程源存储库匹配。

解决方案:

存储本地更改。获取一个干净的文件和目录,忽略 .gitignore 并硬重置为原点。 git stash --include-untracked git fetch --all git clean -fdx git reset --hard origin/master

P
Peter Mortensen

做就是了

git fetch origin branchname
git checkout -f origin/branchname // This will overwrite ONLY new included files
git checkout branchname
git merge origin/branchname

因此,您可以避免所有不需要的副作用,例如删除您想要保留的文件或目录等。

好的。通过首先在我想要合并的分支中使用 checkout -f,这消除了所有有问题的未跟踪文件。然后我可以再次结帐我的目的地,最后合并没有问题。

P
Peter Mortensen

尽管有最初的问题,但对于有类似问题但又不想丢失本地文件的人来说,最重要的答案可能会导致问题。例如,参见 Al-Punk 和 crizCraig 的评论。

以下版本将您的本地更改提交到临时分支 (tmp),检出原始分支(我假设是 master)并合并更新。您可以使用 stash 执行此操作,但我发现简单地使用分支/合并方法通常更容易。

git checkout -b tmp
git add *; git commit -am "my temporary files"
git checkout master

git fetch origin master
git merge -s recursive -X theirs origin master

我们假设 其他存储库origin master

佚名

将索引和头部重置为 origin/master,但不要重置工作树:

git reset origin/master

我个人认为这是最有用的。然后它会保留您的工作树,以便您可以再次签入。对于我的问题,我删除了与添加相同的文件,因此它被卡住了。很奇怪,我知道。

V
Vishesh Chandra

这四个命令对我有用。

git reset --hard HEAD
git checkout origin/master
git branch -D master
git checkout -b master

执行这些命令后检查/拉取

git pull origin master

我尝试了很多,但最终通过这些命令获得了成功。

“git branch -D master”删除分支。所以要小心。我更喜欢使用“git checkout origin/master -b <新分支名称>”来创建一个具有新名称的新分支,而你确实需要 3,4 行。也建议使用“git clean -f”。