我已经把自己处理成一种对我没有意义的情况.我会尽力描述它.
我有一个开发分支,我已经将master合并到了它git checkout develpment && git merge master.我没有在这里得到任何合并冲突.
有一个我感兴趣的具体提交,让我们说它是abcd123.当我跑步时git branch --contains abcd123,它报告两者development并master包含abcd123.当我这样做时git log,它会abcd123在提交列表中显示,包括on development和on master.
git show abcd123显示包含两个文件的更改.但我似乎无法找到这些变化.当我查看文件时,我看不到这些变化,无论是开development还是开master.当我检查时git log -- path/to/file1,我看不到abcd123,同样的git log -- path/to/file2.
这里发生了什么?如何提交,但变化显然不存在?
abcd123最初可能是在development合并到另一个分支(除了)之外引入的master.我不知道这是否会有所作为.
顺便说一句,当我尝试git checkout master && git merge development(合并后master为development如上图所示),我得到了很多的合并冲突,包括文件1和文件2的.所以这似乎表明master实际上没有合并development- git merge development如果git merge master已经执行了,不应该成功吗?引起更多混淆,git branch --merged development说master已合并成development.我猜这与git merge master...... 一致
在这一点上任何建议都非常感谢.
编辑:此时似乎问题是由于合并失败或以某种方式搞砸了.如果有人还在阅读,我认为torek的回答方向似乎最有成效.
tor*_*rek 16
这个答案很长,因为这里有很多事情要做.但是,TL; DR摘要可能就是您想要的--full-history.
这里有多个单独的问题需要解开:
git log -p或git show经常引导人们在解释Git存储的内容时走错路.git log命令有时对你来说(特别是在合并时),纯粹是为了不用无用的信息压倒你.git merge可能有点棘手.它原则上很简单,但大多数人并没有马上得到它.让我们先来看看Git最常见的普通提交.Git中的提交是一个快照(文件名的文件内容).你做了一次提交,然后你改变了一些东西,改变了git add一两个文件并进行了第二次提交,第二次提交的文件与第一次提交完全相同,除了那些被覆盖的提交git add.
值得将这些作为Git 提交图的一部分.请注意,每个提交都有自己唯一的哈希ID(其中一个不可记住的字符串,如93aefc或badf00d或cafedad),以及父(或先前)提交的ID .父提交哈希允许Git以反向方式将这些事物串在一起:
... <-E <-F <-G ...
Run Code Online (Sandbox Code Playgroud)
其中每个大写字母代表一个哈希ID,箭头表示每个提交"指回"到其父代的想法.通常我们不需要绘制内部箭头(最后它们不是很有趣)所以我将它们画成:
...--E--F--G <-- master
Run Code Online (Sandbox Code Playgroud)
但是,该名称 master仍然需要箭头,因为此箭头指向的提交将随时间而变化.
如果我们选择一个类似的提交G并在不使用git log -por的情况下查看它git show,我们将完整地看到每个文件,就像它存储在提交中一样.事实上,当我们用git checkout它来检查它时会发生什么:我们将所有文件全部提取到工作树中,以便我们可以查看和处理它们.但是,当我们用浏览它git log -p或者git show,Git不会告诉我们的一切; 它只告诉我们改变了什么.
为此,Git提取提交及其父提交,然后git diff在该对上运行一个大的.无论父母F和孩子之间有什么不同G,这就是改变了,所以这就是你的表现git log -p或git show表现.
这对普通的单父提交都很好,但它不适用于合并提交.合并提交只是具有两个(或更多,但我们不会担心这种情况)父提交的任何提交.你通过成功获得这些git merge,我们可能会这样画出来.我们从两个分支开始(从一些起点分叉):
H--I <-- development (HEAD)
/
...--E--F--G <-- master
Run Code Online (Sandbox Code Playgroud)
然后我们运行git merge master.1 Git现在尝试将两个分支组合在一起.如果成功,则会生成一个具有两个父项的新提交:
H--I--J <-- development (HEAD)
/ /
...--E--F--G <-- master
Run Code Online (Sandbox Code Playgroud)
该名称development现在指向新的合并提交J.括号中的括号(HEAD)表示这是我们当前的分支.这告诉我们哪个名称被移动:我们进行新的提交 - 包括任何新的合并提交 - 并且development是更改为指向新提交的分支名称.
如果我们不担心如何确定合并提交的内容(各种提交的文件),这一切都非常简单.合并提交就像任何其他提交一样:它有一个完整的快照,一堆包含内容的文件.我们检查合并提交,这些内容像往常一样进入我们的工作树.
但是当我们去查看合并提交时......好吧,Git通常会对其父级进行提交.合并有两个父母,每个分支一个.哪一个应该Git diff,以显示你的变化?
在这里,git log并git show采取不同的方法.当您查看提交时git log,默认情况下它根本不显示任何内容.它不会选择I-vs- J,也不会选择G-vs- J!它根本没有显示任何内容git log -p.
1在某些Git工作流程中,不鼓励从 master 合并到任何其他分支.它可以工作,但是既然你做了,那就让它运行吧.
该git show命令做了一些不同的事情.它运行两个 git diff s,一个用于I-vs- J,一个用于G-vs- J.然后它尝试组合两个差异,只显示两者中的变化.也就是说,Git J不同于I但不是特别有趣的方式,它可以抑制差异.凡J不同于G但不是在一个特别有趣的方式,Git的抑制这种差异也是如此.这可能是最有用的模式,所以它是git show显示的.它仍然非常不完美,但你在这里所做的一切都不适合所有目的.
您可以git log通过添加这样做同样的事情--cc的git log -p选项.或者,您可以通过使用来更改其中一个 git log 或 git show显示合并提交-m(请注意一个破折号-m,--cc顺便说一下两个).
该-m选项告诉Git,出于查看目的,它应该拆分合并.现在Git的比较I来J,向你展示你通过合并所带来的一切G.然后Git比较G分裂的额外版本J,向您展示通过合并带来的所有内容I.由此产生的差异通常非常大,但(或因为)它会显示一切.
有更多方法可以尝试查找某些文件发生的情况,但我们需要暂时停下来才能找到您的文件:
git log -- path/to/file1
Run Code Online (Sandbox Code Playgroud)
命令.就像我们看到git log 跳过合并一样,它可能会跳过更多的东西(但是有办法阻止Git这样做).
让我们再看一下合并前的图:
H--I <-- development (HEAD)
/
...--E--F--G <-- master
Run Code Online (Sandbox Code Playgroud)
这里,分支上有两个development不在分支上的master提交,两个提交master没有打开development.提交E(以及所有早期提交)都在两个分支上.但是提交E是特殊的:它是两个分支上最近的2个提交.提交E是Git称之为合并的基础.
为了执行合并,Git有效地运行了两个git diff命令:
git diff E I
git diff E G
Run Code Online (Sandbox Code Playgroud)
第一个对各种文件产生一组更改,这是"我们在分支上做的development".这是,实际上,总和H以及I如果它们是作为补丁处理.第二个产生,可能不同的设定改变的各种文件,"我们所做的事情上master",和之前有效的总和F,并G作为补丁.
然后Git尝试将这两个差异结合起来.无论是他们之间完全独立的,它需要两个组变化的,它们适用于犯下的内容E,并将其用作结果.无论两个更改集在同一文件中触及同一行,Git都会尝试查看是否只能获取该更改的一个副本.如果两者都修复了文件第33行上单词的拼写README,Git只能获取拼写修复的一个副本.但是无论两个变更集触及同一文件的同一行,但做出不同的更改,Git都会声明"合并冲突",将其隐喻性的手抛向空中,并让您修复产生的混乱.
如果你(或合并的任何人)想要,他们就可以阻止Git提交合并结果,即使Git认为这一切都是顺利进行的:git merge --no-commit master让Git在结合所有内容后停止.此时,您可以在编辑器中打开工作树文件,更改它们,将它们写回,git add更改的文件和git commit合并,以便在合并中放入一些不是来自三个输入中的任何一个(基本和两个分支) -提示).
无论如何,理解所有这些的关键是合并基础提交的概念.如果你坐下来绘制提交图,合并基础通常非常明显,除非图形失控(实际上发生了很多).您也可以让Git为您找到合并基础 - 或者合并基数,复数,在某些情况下:
git merge-base --all master development
Run Code Online (Sandbox Code Playgroud)
这会打印出一个哈希ID.在我们假设的情况下,这将是提交的哈希ID E.一旦你有了,你可以git diff手动运行,看看每个文件发生了什么.或者您可以运行单个文件git diff:
git diff E development -- path/to/file1
git diff E master -- path/to/file1
Run Code Online (Sandbox Code Playgroud)
请注意,如果要更换名称master,并development与该提交的哈希值的ID 是当前之前你做了git merge,这个工程即使后合并.这将告诉你Git认为应该结合的东西path/to/file1.反过来,这将告诉您Git是否没有看到更改,或者是否合并的任何人覆盖了 Git,或者是否错误地处理了冲突的合并.
合并后,后续合并将找到不同的合并基础:
H--I--J----K <-- development
/ /
...--E--F--G--L--M <-- master
Run Code Online (Sandbox Code Playgroud)
我们现在查看两个分支提示并按照历史(向左方向)向后工作,遵循合并的两个分支J,以找到我们可以从两个分支提示获得的第一个提交.从开始K,我们回到J,然后到两个I和G.从开始M,我们回到L,然后去G.我们发现G在两个分支上,因此commit G是新的合并基础.Git将运行:
git diff G K
git diff G M
Run Code Online (Sandbox Code Playgroud)
获取两个更改集以应用于合并库提交G.
2 "最近"这里指的是提交图顺序,而不是时间戳,尽管它可能也是两个分支上最新时间戳的提交.
我们已经看到git log -p只是跳过合并提交.你根本看不到任何差异,好像合并完全是魔术.但是当你跑步时:
git log -- path/to/file1
Run Code Online (Sandbox Code Playgroud)
发生了别的事情,甚至更加阴险.在" 历史简化 "一节的(长)git log文档中对此进行了描述,尽管相当不透明.
在上面的例子中,假设git log是从K后面走.它发现J,这是一个合并.然后它会检查两者,I并在排除除了您正在查看的文件之外的所有文件之后G进行比较J . 也就是说,它只是path/to/file1在三次提交中进行比较.
如果合并的一侧未显示任何更改path/to/file1,则表示合并结果J与输入(I或G)没有区别.Git称之为"TREESAME".如果合并J,在被剥离到这个文件后,匹配I或G类似地剥离,那么J是TREESAME I或G(或两者).在这种情况下,Git会选择或者任何一个TREESAME父级,并仅查看该路径.让我们说它选择I(沿着顶行)而不是G(沿着底部).
这意味着在我们的情况是,如果有人在合并过程中放弃了球,失去了本来应该进来的改变J从F,git log从不显示它.该log命令查看K,然后J,然后查看,但下降G的,只有在看I,然后H,然后E,然后任何早期的提交.它从来没有看过提交F!所以,我们看不到的变化,以path/to/file1从F.
这里的逻辑很简单; 我将git log直接引用文档,但增加一些重点:
[默认模式]将历史简化为最简单的历史记录,解释树的最终状态.最简单的,因为如果最终结果相同,它会修剪一些侧枝...
由于更改F被删除,Git声明它们无关紧要.你不需要看到它们!我们完全忽略合并的那一面!
你可以完全打败这个--full-history.这告诉Git 不要修剪合并的任何一方:它应该看不起这两个历史.这将为F您找到承诺.添加-m -p应该也发现其中的变化被丢弃,因为它会发现所有的那一抹文件提交:
git log -m -p --full-history -- path/to/file1
Run Code Online (Sandbox Code Playgroud)
如果更改存在(在F我们的示例中为commit )并且不再存在,则只有两种方法丢失:
它们git revert在普通提交中被还原(使用或手动).path/to/file1即使没有-m,你也会将此视为一个触及历史的提交; -p会告诉你差异.
或者,它们在合并期间被丢弃而丢失.即使没有-m,你也会看到合并,但不确定无论谁做了合并,都会把球扔到这里; 但-m -p会显示两个父差异,包括应该(但没有)接受更改的差异.