Git:为什么我没有看到我检查过的文件的最新更改?

时间:2017-10-25 23:11:06

标签: git

我正在本地分支机构工作,我知道我必须对其进行更改但尚未更改的文件已被其他开发人员更改。在我开始自己更改文件之前,我想要这些更改。我可以看到该文件已被更改,例如,显示我们的git repo的基于Web的工具。我做过像git fetch remotes / origin / develop(这是所有开发人员推送的分支的名称)然后git checkout changedFile.java当我执行git日志或使用gitk时我仍然没有看到最新的更改。我错过了什么?

编辑:我的想法是,如果您有一个除开发之外的本地分支,您无法从远程开发更新该分支上的文件?

编辑:git checkout origin / develop - path / to / changedFile.java尽我所能确切地知道我想要什么,让我进一步激励:我正在我的本地分支和远程开发(这不是我工作的本地分支的名称)偏离。我即将更改其中一个文件,并且该特定文件已更改。在我看来,我可以使用该文件的版本,而不需要以后的更改,并在以后进行合并或获得更改,并可能更容易合并。所以结帐工作,我唯一的问题是,为什么这是错误的事情呢?

2 个答案:

答案 0 :(得分:2)

TL; DR

如果您只想查看该文件,请使用git show,例如:

git show origin/develop:changedFile.java

如果您使用git checkout origin/develop -- changedFile.java,那么会通过您的索引将其提取到您的工作树中,但这通常是一个好主意。

关于提交和索引/登台区域

的前提条件

Git就是提交。提交不是文件,虽然提交实际上包含文件。更准确地说,每个提交都包含每个文件的完整快照,处于您(或任何人)提交时的状态。 (即使这不是很正确。)

为了进行 new 提交,Git为您提供了两个处理文件的地方。其中之一,称为工作树,非常明显。工作树中的文件具有计算机一直处理的普通表单。它们可以被读取,写入,就地更新,附加,等等。换句话说,工作树就是你工作的地方。

由于各种原因,Git允许您在工作树中拥有赢得提交的文件。这些是未跟踪的文件。 Git对未跟踪文件没有任何作用,除了经常抱怨它们没有跟踪。要关闭它,您可以在.gitignore中列出特定的未跟踪文件,这些文件并不能使Git 忽略它们,它只是关闭它们的未跟踪状态,并使它不是git add如果你使用一个群体"添加一切"操作。 (请注意,如果已经跟踪了某个文件,则在.gitignore中列出该文件无效。)

还有每个跟踪文件的另一个副本。这个额外的副本,称为索引 staging-area 副本,实际上是Git知道它是一个被跟踪的文件。这些副本始终存在,事实上,当您进行新的提交时,Git从索引副本进行提交,而不是从工作树副本进行提交!这就是为什么Git经常要求你git add的事情:git add命令意味着"从工作树复制到索引"。它只是在您说git add时进行复制;如果再次更改文件,则必须重新复制。

运行git commit时,Git打包当前索引内容(每个文件的另一个新副本!),您的姓名和电子邮件地址以及当前时间,您编写的提交消息以及哈希ID当前或HEAD提交。然后,它会从所有这些内容中进行 new 提交,并使当前分支名称(存储在HEAD中)指向您刚刚创建的新提交。这个提交(大部分)是永久的和(完全)只读的,因此它可以永久保存你所做的事情,或者直到你明确地让它消失(即使那时Git倾向于坚持至少30天并且#34;以防万一")。

我们可以通过写下他们的丑陋哈希ID并用箭头将每个提交连接到其父提交来绘制您的提交和所有其他提交。我们使用当前分支名称中较大的箭头:

... <-194ab72  <-c309ac4   <-- develop

由于哈希ID很大而且很笨拙,我们可以用单个大写字母代表这些,只要我们永远不需要写下超过26个提交:

... <-G <-H   <-- develop

每次提交都会记住其父级;但由于承诺不可更改,父母不记得他们的孩子。因此,Git必须(并且确实)始终向后工作。分支名称develop存储您develop上的最新提交。要进行新的提交,只需将其添加到您的链中:

...--G--H--I   <-- develop

(因为内部箭头总是倒退而且永远不会改变,我们现在几乎可以停止绘制它们了。)

git show可以显示任何内容

不带参数运行git show会显示您当前的提交,打印其日志消息,然后将其与父节点进行比较。这会将快照转换为自上一个快照以来的更改&#34;。

正在运行git show origin/develop会显示位于origin/develop一角的提交。它执行相同的操作:打印日志消息,然后将提交与其父级进行比较,以查看自其父级以来发生了哪些更改。

正在运行git show origin/develop:path/to/file.txt会在path/to/file.txt指定的提交中显示origin/develop的内容。

现在您已了解上述内容,以下是如何使用它

你一直在研究一些代码。也许你已经提交了,也许没有。您在工作树中有一些更改。其他人在其他存储库中进行了一些其他更改,并提交了它(制作完整的快照)并推送了他们的提交,以便它们进入origin/develop

您运行git fetch origin更新了origin/develop以记录其新提交。让我们画出:

...--G--H--I   <-- develop
            \
             J   <-- origin/develop

您可以而且应该做的是立即提交您自己的代码。让我们也画出来:

...--G--H--I--K   <-- develop
            \
             J   <-- origin/develop

现在您可以使用git mergegit merge所做的是将您的工作与他们的工作结合起来,并且 - 至少在这种情况下,只要Git本身认为合并工作 - 制作 new 提交保存,作为(主要)永久和(完全)不可更改的快照,结合的结果:

...--G--H--I--K--M   <-- develop
            \ __/
             J   <-- origin/develop

或者,您可以使用git rebasegit rebase做的是复制提交,在将它们复制到新的和改进的提交之后,放弃原始文件。 (这是提交的正常持久性被撤消的地方。)如果您将提交K复制到父级为K'的新的J,我们可以像这样绘制:

...--G--H--I--K   [abandoned]
            \
             J   <-- origin/develop
              \
               K'  <-- develop

Merge和rebase都使用合并机制并且合并为动词

这个复制过程的有趣之处在于它使用相同的底层代码来合并git merge使用的文件更改。所谓的合并基础计算有什么不同,但对于这个特殊的简单情况,合并基础在两种情况下都是提交I

当Git进行合并时,会发现自该合并基础以来哪些文件发生了变化,并确定了你做了什么&#34; (对那些文件)和&#34;他们做了什么&#34; (对于相同的文件)。

如果你和他们改变了所有不同的文件,一切都很简单。 Git只是从基础直接获取所有未更改的文件,所有您的已更改的文件都来自您的提交,所有他们的已更改的文件来自其提交。如果您同时更改了相同的文件,Git会尝试合并您的更改及其更改。只要这些变化不会(似乎)重叠,Git就会认为它已经成功地将它们组合在一起。

这个动作,从一个共同的起点(共享提交)开始,结合了两组更改,是Git在用作动词时由 merge 表示的意思。请注意, merge 也可以用作形容词,但是: merge commit 是一个记录两个父提交的提交,例如上面示例中的M。形容词甚至成为名词:这个提交是合并

合并组合提交,合并的分支只是那些分支 - 即使它们没有名称。例如,假设您发现合并提交M是完美的。它完全符合你的要求。您可git pushorigin,之后图片会变为:

...--G--H--I--K--M   <-- origin/develop, develop
            \ __/
             J

这里有一个分支,即使没有分支 name 指向提交J。提交M点以提交J(它有两个父项,KJ)。作为合并提交,M用于将两个分支绑定在一起。

你应该改变还是合并?

这个问题没有一个正确的答案。重新定位会让事情看起来更好,就好像你甚至没有开始一样,直到他们完成了他们的改变。在您放弃原始提交K以支持修订/改进的K'后,我们可以将此图转为:

...--G--H--I--K   [abandoned]
            \
             J   <-- origin/develop
              \
               K'  <-- develop

成:

...--G--H--I   K'  <-- develop
            \ /
             J   <-- origin/develop

然后我们可以删除小刻度标记(&#34; prime&#34;)符号并推送您的提交,以便origin/develop现在包含您的提交:

...--G--H--I--J--K   <-- origin/develop, develop
与合并版本相比,历史看起来如此简单。但这不是实际的历史,而是修订/清理过的历史。这很好(易于使用)和坏(如果修改破坏了某些东西)。

如果你还没有完成怎么办?

如果您还没有真正完成更改,那么重新定位会让您有机会稍后完成更改。或者,你可以简单地不合并。只要您没有git push - 提交,您就可以使用git commit --amend 似乎就地更改当前/最新的提交。您只需正常工作git add您的文件,然后运行git commit --amend而不是git commit。 Git将您当前的提交和#34;推到一边#34;,使您的新提交作为其父提交,在当前提交之前提交。如果K是您当前的提交,我们可以将其绘制为:

       K   [abandoned]
      /
...--J--K'   <-- develop

你可以多次重复这个;每个人都推开另一个提交并在最后插入新的提交:

      K   [abandoned]
     /
     | K'   [abandoned]
     |/
...--J--K''' <-- develop
      \
       K''  [abandoned]

请注意,您可以使用尚未git merge编辑的提交执行此操作(如果K的父级是I,因为您没有git rebase {1}}或者)。如果您 运行git mergegit commit --amend对您没有任何好处,因为最新的提交将是您的合并提交。

(如果已经合并但未推送,则可以&#34;退出&#34;合并。当rebase副本提交时,它显式跳过合并但是,在某些情况下,这会变得有点甚至很棘手。)

未来阅读

请注意,Git提供了交互式 rebase模式。使用交互式rebase,您可以重新排列和组合提交,只要它们是未推送(未发布)的提交。这意味着您可以安全地提交正在进行的快照,即使是微小的更改,也可以用于任何特定目的。之后,当他们真的准备就绪时,您可以使用交互式rebase将它们全部合并为一个大提交,或者几个小但独立的提交。你可以让它看起来像你一直知道你在做什么,即使你不得不尝试一些东西并撤消它们中的一些。

答案 1 :(得分:0)

尽管@ torek的答案是全面的,并且完全解释了如何使用git,但我建议您首先使用所有分支可视化您的提交树,并期望特定的文件内容分支和提交。

对我来说,执行此操作的最佳工具是gitk - 使用c查看 local 存储库中的实际提交树。但根据您的平台,您可能更喜欢其他GUI客户端/