从 github 回购中提取时如何有选择地不合并

How to selectively not merge when pulling from github repo

假设我已将 github 存储库克隆到我的计算机,并在本地更改了其中一些文件,但是当我创建新的 git pull 时 [=16] =] 想以任何方式与这些文件的 github 回购版本合并。也就是说,我希望我对这些本地文件的更改不会以任何方式被存储库的版本取代或更改——尽管我确实想继续从存储库中获取任何新文件。另一种说法可能是,您如何选择要合并的文件和不合并的文件?我知道如果我最后更改文件我应该做一个 commit...除此之外我迷路了。

首先,使用 git fetch 而不是 git pull。现在您在远程跟踪分支中拥有所有新文件,但您自己的本地分支和工作区不受影响。例如,如果您在分支 mybranch 上并且您的远程名为 origin,则新的(和更改的)文件位于 origin/mybranch 但工作区未更改。

现在只需在远程跟踪分支中找到所有新文件(您可以使用 git diff 轻松找到它们,例如 git diff mybranch origin/mybranch),然后 checkout 将这些文件放入工作区。例如,如果您在分支 mybranch:

git checkout origin/mybranch -- anewfile.txt anothernewfile.txt

虽然 matt 的回答听起来很简单(实际上这个过程还可以变得更简单),但它可能会导致问题。

第一个问题是...是的,这些步骤将(一次)按书面方式工作,但它们会让您处于不清楚下一步应该做什么的状态。

您提到了提交本地更改,因此假设您的起点如下所示:

... O <--(origin/master)
     \
      A <--(master)

也就是说,您从 origin 克隆了存储库,并且 master 处于提交 O(可能有任意历史记录;这在这里无关紧要)。您进行了一些更改并提交了它们,创建了提交 A;您的本地 master 现在位于 A,已签出。

你做了 git fetch,结果 origin/master 上有新的提交。现在你有

... O -- R <--(origin/master)
     \
      A <--(master)

你的本地分支和工作树确实没有改变,到目前为止一切顺利。现在您说您想要确定远程主机上有哪些文件是您本地主机上没有的。你可以做类似

的事情
git diff --name-only --diff-filter=A master origin/master

这将为您提供从 master 移动到 origin/master 时将添加的任何文件的名称 (--diff-filter=A)。除了从远程获取的新提交创建的文件外,这还会显示您在本地主服务器上删除的所有文件。如果这是一个问题,你可以做类似

的事情
git diff --name-only --diff-filter=A $(git merge-base master origin/master) origin/master

这会找出您的本地分支与原始分支的分歧,并将 origin/master 与其进行比较,而不是直接将其与您的分支进行比较。另一方面,如果您和远程都创建了一个文件,那么如果您使用此版本的命令,它将包含在列表中,但如果您使用较早的版本则不会。

因此,如果您正在创建 and/or 删除文件,那么您必须考虑哪个比较有意义(或同时查看两者,或其他);但如果您只是编辑现有文件,那么您可以使用其中之一。

好的,很好,假设您有自己的清单。然后您将该列表提供给 `git 结帐。如果您愿意,也可以将其自动化

git checkout origin/dev -- $(git diff --name-only --diff-filter=A master origin/master)

现在所有新文件都作为未提交的新文件出现在您的工作目录(和索引)中。这似乎没有意义——他们是在远程承诺的,对吧?但是您仍然检查了本地提交 A,并且在该上下文中文件未提交。

你可以提交它们。然后图片会像

... O -- R <--(origin/master)
     \
      A -- B <--(master)

其中 B 似乎创建了从远程添加的文件。换句话说,B 包含来自远程的一些(但可能不是全部)更改。 (虽然上图只显示了来自远程的一个新提交,但在实际情况下,更改可能来自任意数量的新提交。)

没关系,但如果您想将分支与 origin/master 重新组合,可能会导致一些额外的工作。

现在假设您进行了更多更改,并再次从远程获取:

... O -- R -- S -- T <--(origin/master)
     \
      A -- B -- C <--(master)

好吧,你可以再做一次

diff --name-status --diff-filter=A master origin/master

这次你不能真正使用 merge-base 变体。如果您在某处记录了您之前合并了高达 R 的更改,那么您可以

diff --name-status --diff-filter=A origin/master~2 origin/master

(基于看到 R 之后有 2 个新提交)。所以这个过程有点可重复,但随着你的进行,它确实会变得有点复杂。我想通过始终将标签移动到您从中复制文件的最后一次提交,您可以使它更容易一些。

而且,您越来越偏离遥控器中发生的事情。 可能不重要..或者可能。

例如,如果 repo 包含单个软件项目的源代码,那么您复制的更改可能取决于您忽略的更改(风险会随着时间/引入的更改数量而增加)。当然,根据您的回购协议的性质,可能 不适用于您,尽管那是非典型的。

所以最重要的是 - 也许这一切都适合您,并且此版本的程序可能会满足您的需求。但这真的不是我推荐在任何类似于典型项目的情况下与遥控器交互的方式。