关于版本控制:如何强制”git pull”覆盖本地文件?

How do I force “git pull” to overwrite local files?

如何强制覆盖git pull上的本地文件?

场景如下:

  • 团队成员正在修改我们正在处理的网站的模板
  • 他们正在向images目录添加一些图像(但忘记在源代码管理下添加它们)
  • 他们稍后会把照片邮寄给我
  • 我正在源代码管理下添加图像,并将它们与其他更改一起推送到Github
  • 他们无法从GitHub中提取更新,因为Git不想覆盖他们的文件。

这是我得到的错误:

error: Untracked working tree file 'public/images/icon.gif' would be overwritten by merge

如何强制Git覆盖它们?这个人是一个设计师——通常我用手解决所有的冲突,所以服务器有他们只需要在计算机上更新的最新版本。


重要提示:如果您有任何本地更改,它们将丢失。无论是否有EDOCX1[0]选项,任何未被推送的本地提交都将丢失。[*]

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

我认为这是正确的方法:

1
git fetch --all

然后,您有两个选项:

1
git reset --hard origin/master

或者如果你在其他分支机构:

1
git reset --hard origin/<branch_name>

说明:

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

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

维护当前本地提交

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

1
2
3
4
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中。

未提交的更改

但是,未提交的更改(甚至是阶段性更改)将丢失。确保藏匿和承诺任何你需要的。为此,您可以运行以下命令:

1
git stash

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

1
git stash pop


试试这个:

1
2
git reset --hard HEAD
git pull

它应该做你想做的。


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

有时仅仅是clean -f没有帮助。如果您有未跟踪的目录,还需要-d选项:

1
2
3
4
5
# WARNING: this can't be undone!

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

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

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

1
git clean -n -f -d

实例输出:

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


像刺猬一样,我认为答案很糟糕。但尽管刺猬的回答可能会更好,但我认为它并没有它所能做到的那么优雅。我发现做到这一点的方法是使用"fetch"和"merge"以及定义好的策略。它应该使您的本地更改保持不变,只要它们不是您试图强制覆盖的文件之一。

首先提交您的更改

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

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

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

"-x"是选项名,"their"是该选项的值。您选择使用"他们的"更改,而不是在发生冲突时使用"您的"更改。


而不是:

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

我建议你做以下工作:

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

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


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

1
git clean

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


警告:如果您的gitignore文件中有任何目录/*条目,执行此操作将永久删除您的文件。

有些答案似乎很糟糕。按照大卫·阿夫萨贾尼什维利的建议,对@lauri所发生的事情感到可怕。

而是(Git>v1.7.6):

1
2
git stash --include-untracked
git pull

以后你可以清理藏匿的历史。

手动,逐个:

1
2
3
4
5
6
$ git stash list
stash@{0}: WIP on <branch>: ...
stash@{1}: WIP on <branch>: ...

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

残忍地,一下子:

1
$ git stash clear

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

1
2
3
$ git stash list
...
$ git stash apply stash@{5}


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

1
git checkout <your-branch> -f

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

1
git clean -f

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

1
git clean -fd


不要与git pull合并,请尝试以下操作:

git fetch --all

然后:

git reset --hard origin/master


唯一对我有用的是:

1
git reset --hard HEAD~5

这将使您恢复五次提交,然后

1
git pull

我通过查找如何撤消Git合并发现了这一点。


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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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
  • 第一个命令获取最新数据。

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

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

  • 最后,我们执行一个pull来更新到最新版本,但是这次没有任何冲突,因为repo中的未跟踪文件不再存在,并且所有本地修改的文件都已经与存储库中的文件相同。


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

我通过以下方式解决了:

  • 删除所有文件。只留下.git目录。
  • git reset --hard HEAD
  • git pull
  • git push
  • 现在它起作用了。


    首先,尝试标准方法:

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

    警告:只有在未提交以上命令的情况下,这些命令才能导致数据/文件丢失!如果不确定,请首先备份整个存储库文件夹。

    然后再拉一次。

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

    1
    2
    3
    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文件(except .git/dir,其中您有所有提交)并再次将其拉入。

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

  • .gitattributes file中的海关规则

    在.gitattributes中使用eol=lf规则可能会导致git通过在某些文本文件中将crlf行尾转换为lf来修改某些文件更改。

    如果是这种情况,您必须提交这些CRLF/LF更改(通过在git status中查看它们),或者尝试:git config core.autcrlf false暂时忽略它们。

  • 文件系统不兼容

    使用不支持权限属性的文件系统时。例如,您有两个存储库,一个位于Linux/Mac(ext3/hfs+上),另一个位于基于FAT32/NTFS的文件系统上。

    正如您所注意到的,有两种不同类型的文件系统,所以不支持Unix权限的文件系统基本上无法重置不支持该类型权限的系统上的文件权限,因此无论您如何尝试--hard,Git总是检测到一些"更改"。


  • 奖金:

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

    git pull --rebase

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

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

    在"git pull--rebase"中查找详细信息?.


    我也有类似的问题。我必须这样做:

    1
    2
    3
    git reset --hard HEAD
    git clean -f
    git pull


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

    为此,我更新了库斯塔迪奇的剧本。我还修正了一个打字错误(原文中缺少一个)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #/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 pull而不出错:

    1
    2
    3
    4
    5
    git fetch --all
    git reset --hard origin/master
    git reset --hard HEAD
    git clean -f -d
    git pull

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


    我认为冲突有两个可能的原因,必须分别解决,据我所知,上述任何一个答案都不能解决这两个问题:

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

    • 也需要删除不在远程分支上的本地提交。在我看来,实现这一目标最简单的方法是:git reset --hard origin/master(用你正在从事的任何分支来代替"master",并首先运行git fetch origin)


    这里的大多数答案似乎都集中在master分支上;但是,有时我在两个不同的地方处理同一个功能分支,我希望在一个分支中重新平衡,而不需要太多的跳跃。

    基于RNA的答案和Torek对一个类似问题的答案的结合,我想出了一个非常有效的方法:

    1
    2
    git fetch
    git reset --hard @{u}

    从一个分支运行这个,它只会将本地分支重置为上游版本。

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

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

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

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

    享受!


    更简单的方法是:

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

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


    我也有同样的问题,出于某种原因,即使是一个git clean -f -d也不会这样做。原因如下:由于某种原因,如果您的文件被Git忽略(我想是通过.GitIgnore条目),它仍然会担心用一个稍后的pull覆盖这个文件,但是clean不会删除它,除非您添加-x


    我自己解决这个问题的方法是:

    1
    2
    3
    4
    5
    6
    7
    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:

    1
    git checkout master && git merge tmp

    下一次,你可以通过查找"git stash分支"以更干净的方式处理这个问题,尽管stash可能会在最初的几次尝试中给你带来麻烦,所以在一个非关键项目上做第一次实验……


    我知道一种更简单、更不痛苦的方法:

    1
    2
    3
    4
    $ git branch -m [branch_to_force_pull] tmp
    $ git fetch
    $ git checkout [branch_to_force_pull]
    $ git branch -D tmp

    就是这样!


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

    1
    git rm [file]

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


    这四个命令对我有用。

    1
    2
    3
    4
    git reset --hard HEAD
    git checkout origin/master
    git branch -D master
    git checkout -b master

    执行这些命令后检查/拉

    1
    git pull origin master

    我试了很多次,但最终还是成功了。


    尽管有最初的问题,最重要的答案可能会给有类似问题但不想丢失本地文件的人带来问题。例如,参见al-punk和crizcraig的评论。

    下面的版本将您的本地更改提交到一个临时分支(tmp),检查原始分支(我假设是master)并合并更新。您可以使用stash来完成这项工作,但我发现使用分支/合并方法通常更容易。

    1
    2
    3
    4
    5
    6
    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


    只要做

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

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


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

    1
    git reset origin/master


    我通读了所有的答案,但我在寻找一个单一的命令来做这件事。这是我做的。在.gitconfig中添加了git别名

    1
    2
    [alias]
          fp ="!f(){ git fetch ${1} ${2} && git reset --hard ${1}/${2};};f"

    将命令运行为

    1
    git fp origin master

    相当于

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

    要求:

  • 跟踪局部变化,这样这里就不会有人丢失它们。
  • 使本地存储库与远程源存储库匹配。
  • 解决方案:

  • 隐藏局部变化。
  • 清除文件和目录后提取忽略.gitignore并硬重置为原点。

    1
    2
    3
    4
    git stash --include-untracked
    git fetch --all
    git clean -fdx
    git reset --hard origin/master

  • 不要使用git reset --hard。这将消除他们的变化,而这很可能是完全不受欢迎的。而是:

    1
    2
    3
    git pull
    git reset origin/master
    git checkout <file1> <file2> ...

    当然,你可以使用git fetch而不是git pull,因为它显然不会合并,但是如果你经常拉它,继续拉它是有意义的。

    因此,这里发生的情况是,git pull更新您的源/主引用;git reset更新您的本地分支引用,使其与源/主引用相同,而不更新任何文件,因此您的签出状态不变;然后,git checkout根据需要将文件还原到您的本地分支索引状态。如果在活动主机和上游主机上添加了完全相同的文件,则在重置后索引已经与文件匹配,因此在常见情况下,根本不需要执行git checkout

    如果上游分支还包含要自动应用的提交,则可以对流程进行细微的更改:

    1
    2
    3
    4
    5
    git pull
    git merge <commit before problem commit>
    git reset <problem commit>
    git checkout <file1> <file2> ...
    git pull

    这是恢复更改的最佳实践:

    • git commit提交您的阶段性更改,以便将它们保存在reflog中(见下文)
    • git fetch获取最新的上游变更
    • git reset --hard origin/master硬复位到原点主分支

    reflog记录本地存储库中正在更新的分支和其他引用。或者简单地说,反应就是你变化的历史。

    所以这总是一个很好的实践承诺。提交被附加到reflog中,这样可以确保始终有一种方法来检索已删除的代码。


    我使用这个命令来清除本地文件,防止我执行拉/合并操作。但是要小心!首先运行git merge …查看是否只有您真正想要删除的文件。

    1
    git merge origin/master 2>&1 >/dev/null | grep ^[[:space:]] | sed s/^[[:space:]]//g | xargs -L1 rm
    • git merge列出了所有这些文件。它们被一些空白区域所覆盖。
    • 2>&1 >/dev/null将错误输出重定向到标准输出,以便由grep接收。
    • grep ^[[:space:]]只过滤具有文件名的行。
    • sed s/^[[:space:]]//g从一开始就修剪空白。
    • xargs -L1 rm调用每个文件上的rm,删除它们。

    小心处理:无论git merge输出是什么,都会为以空白开头的每一行调用rm


    我在尝试使用Angular2 Webpack启动程序上的Material2分支,并经历了一段很长的时间。这是我下载和使用该分支的唯一方法。

    1
    2
    3
    4
    5
    git clone --depth 1 https://github.com/angularclass/angular2-webpack-starter.git

    cd angular2-webpack-starter/

    git checkout -b material2

    打开项目文件夹并删除所有非隐藏文件和文件夹。留下所有隐藏的。

    1
    2
    3
    4
    5
    6
    7
    git add .

    git commit -m"pokemon go"

    git reset --hard

    git pull origin material2

    (当编辑器弹出时,点击":wq",然后按enter)

    现在你准备好了。


    可以忽略项目基文件夹中包含文件的文件:

    吉蒂格诺

    1
    public/images/*

    然后拉出更改,然后从gitignore文件中删除该行。


    在Windows上,执行以下单个命令:

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


    1:重置为上一个提交

    1
    git reset --hard HEAD

    2:删除未跟踪的文件

    1
    git clean -f

    3:做出承诺

    1
    git pull

    资料来源:

    • https://git-scm.com/docs/git-reset
    • https://git-scm.com/docs/git-clean/

    如果要以常规方式重置到远程跟踪分支,请使用:

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

    如果还想重置本地更改:

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