git pull 保留本地未提交的更改

213

如何安全地更新(pull)git项目,即使有上游更改,也保持特定文件不变?

myrepo/config/config.php

即使该文件在远程上被更改,当我进行git pull时,是否有一种方法可以更新其他所有内容,但是保持此文件不变(甚至不合并)?

附注:我需要做我所要求的事情,因为我只编写基于git的部署脚本。 我无法将配置文件更改为模板。

因此,我需要编写更新脚本的方法,以不丢失本地更改。 我希望有像以下这样简单的方法:

git assume-remote-unchanged file1
git assume-remote-unchanged file2

然后执行 git pull


config.php 的更改已经提交了吗? - Mark Longair
1
可能是重复的问题:在进行git合并时,是否可能排除特定提交? - Daenyth
1
它还没有提交。我宁愿不必这样做。 - Johnny Everson
@JhonnyEverson:它属于同一类问题(你有一个配置文件,不想提交特定的设置,但需要跟踪配置文件结构。) - Daenyth
7个回答

380

有一个基于Git stash的简单解决方案。将所有已更改的内容存储到stash中,拉取所有新内容,然后应用你的stash。

git stash
git pull
git stash pop

在弹出stash时可能会发生冲突。在您描述的情况下,实际上会有一个config.php的冲突。但是,解决这个冲突很容易,因为您知道您放入stash中的内容就是您想要的。所以,请执行以下操作:

git checkout --theirs -- config.php

7
git checkout --theirs 命令非常令人困惑。它有时会按我所需执行操作,但其他时候则会出现严重问题。你有没有相关的好文档可以提供? - Milimetric
4
有时候,“theirs”和“ours”可能会让人感到困惑。在 git merge 中,“ours”指的是当前工作目录中的内容。但在 git rebase(或 git rebase -onto)中,含义可能会发生交换。 - GoZoner
2
git stash, git pull, git stash apply你可以使用以下命令删除stash: git stash drop 一旦成功合并更改。 - BeingSuman
33
使用git的问题在于你必须理解它将要做什么。另一个使用git的问题是,即使对于聪明的人来说,理解git将要做什么也经常非常困难。 - Bradley Thomas
4
你应该检查是否有需要隐藏的内容。否则,你会从之前的 git stash 中弹出已隐藏的更改。 - Jörn Reimerdes
显示剩余5条评论

21

我使用

git pull -X ours

这将指示git在合并时使用本地版本。


请注意,问题已经改进以澄清它是关于“未提交的更改”的。因此,这个带有未提交更改的答案将导致以下错误: 错误:无法使用rebase拉取:您的索引包含未提交的更改。 错误:请提交或存储它们。 - Valerio Bozz
非常好的观点。 - Peter Cotton

17
如果您的代码库中有一个文件,大多数拉取者都希望对其进行自定义,则将该文件重命名为类似于config.php.template的名称,并将config.php添加到您的.gitignore文件中。

6
也可以查看 这个答案,使用 .gitattributes 可以在合并时始终保留你的更改。 - KurzedMetal
这更接近我所需要的。模板是一种优雅的解决方案,但我担心我不能使用它,因为我只是编写部署脚本。 - Johnny Everson

7
更新:这个回答确实回答了问题,但我认为KurzedMetal的回答才是你想要的。

假设:

  1. 你现在在分支master
  2. 上游分支是origin中的master
  3. 你没有未提交的更改

... 你可以执行:

# Do a pull as usual, but don't commit the result:
git pull --no-commit

# Overwrite config/config.php with the version that was there before the merge
# and also stage that version:
git checkout HEAD config/config.php

# Create the commit:
git commit -F .git/MERGE_MSG

如果您需要经常这样做,您可以为此创建一个别名。请注意,如果您有未提交的更改config/config.php,这将会使它们丢失。


7

6
我们也可以尝试使用带有rebase的git pull。
git pull --rebase origin dev

请注意,问题已经改进以澄清它是关于“未提交的更改”的。因此,这个带有未提交更改的答案将导致以下错误: 错误:无法使用rebase拉取:您的索引包含未提交的更改。 错误:请提交或存储它们。 - Valerio Bozz

2
回答问题:如果您想在checkout时排除某些文件,可以使用sparse-checkout
  1. .git/info/sparse-checkout中定义您想要保留的内容。这里,我们想要全部(*)但是(请注意感叹号)config.php:

    /*
    !/config.php

  2. 告诉git您想考虑sparse-checkout。

    git config core.sparseCheckout true

  3. 如果您已经在本地拥有此文件,请执行git在稀疏checkout上的操作(通过设置“skip-worktree”标志来告诉它必须排除此文件)。

    git update-index --skip-worktree config.php

  4. 享受一个您自己的config.php文件的存储库 - 无论存储库上有什么更改。


请注意,配置值不应该在源代码控制中:

  • 这是潜在的安全漏洞
  • 它会导致部署等问题

这意味着你必须将它们排除在外(在第一次提交之前将它们放入 .gitignore 文件中),并在每个实例上创建适当的文件来检出你的应用程序(通过复制和调整“模板”文件)。

请注意,一旦文件由 git 接管,.gitignore 将不起作用。

鉴于此,一旦文件已在源代码控制下,你只有两个选择 ():

  • 重置所有历史记录以删除该文件(使用 git filter-branch

  • 创建一个删除该文件的提交。这就像是在打一场失败的战斗,但是,嗯,有时你必须接受这个事实。


这个完美地运作了!我引用手册上的内容:git read-tree 和其他基于合并的命令(如 git mergegit checkout 等)可以帮助维护跳过工作树位图和工作目录更新。 $GIT_DIR/info/sparse-checkout 用于定义跳过工作树参考位图。当 git read-tree 需要更新工作目录时,它会基于该文件重置索引中的跳过工作树位,该文件使用与 .gitignore 文件相同的语法。如果条目与此文件中的模式匹配,则不会在该条目上设置跳过工作树。否则,将设置跳过工作树。 - Onno Rouast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接