我是一名熟悉高级编程语言(如C#或Python)的程序员,但我最近开始深入研究Git的复杂性。上下文:我正在开发一个游戏,我有一个development
分支,其中包含一个特定的'Development'
目录,为了保持master
,它不会被合并到master
。 1}}干净。
我来到this answer几乎完成了工作;但是,这个方法,虽然它不会提交对目录的更改,仍然会在master
分支上创建它,这意味着每次合并后,我仍然需要返回并手动删除文件。
我正在设置一个别名git publish
来自动执行此任务,我将在此处发布完整性:
[alias]
publish = "!f(){ git checkout master \
&& git merge --no-commit --no-ff development \
&& git reset -- Assets/Development/ \
&& git commit \
&& git push; };f"
我想知道,有什么方法可以阻止在Assets/Development/
上创建master
吗?
答案 0 :(得分:1)
旁注:由于.gitignore
的性质,.gitignore
无法摆弄,因为.gitignore
不是真的"要忽略的文件",而是&# 34;在某些情况下压制某些抱怨和/或随意销毁的文件" (这并不意味着您不应该因为其他原因而调整--no-commit
,只是因为它确实做希望这些文件版本化在开发部门。)
一个技巧基本上就是你现在正在做的事情:进行合并(使用git reset -- Assets/Development/
),然后删除你不想要的东西。
剥离步骤是这样的:
--mixed
这使用git reset
(默认情况下,并在给出路径时强制给你)形式Assests/Development/
,它设置(或"重置",真的)索引以匹配指定路径的指定树。这里的路径是HEAD
,即该子目录中的所有内容。指定的树没有指定 - 因此它默认为HEAD
,或者更确切地说是HEAD
的树。 master
是当前分支的当前提交,当然是master
,因为我们刚刚检查过;并且Assets/Development/
根本不包含Assets/Development/
,因此重新设置的索引现在不再具有该子树。
简而言之,因为HEAD
不在git add
,所以这会撤消git merge
对Assets/Development
中所有内容所做的git reset --hard -- Assets/Development/
。问题是虽然这会删除索引中的条目,但它会将它们留在工作树中。
有人可能会尝试rm -r Assets/Development
,但是git不会这样做:在提供路径时无法指定重置模式。但是,这留下了三个更明显的选择:
添加git reset
(在commit
之前或之后,或甚至在git rm -rf Assets/Development/
步骤之后)
这会删除文件,因此当它们从索引和工作树中删除时,您可以提交并完成。
使用git reset
(代替git clean
)
这将删除索引条目,删除工作树文件(和目录),因此您可以提交并完成。
提交后使用git merge <commit>
。这可能比你想做的更多。
主要的是,你可能只需要做一次,而不是重复。这取决于你在此过程中所做的改变。
当你运行master
时,git首先找到合并基础。
合并基础在图表中两个节点之间的提交图中定义为 L owest C ommon A ncestor(LCA) 。这两个节点是您当前的提交 - 在这种情况下是分支git merge
的提示 - 以及您对development
的提交,在这种情况下是分支master
的提示。 LCA的定义需要一点图论,但从宽松的角度讲,它是最近的&#34;提交在两个提交历史记录上。
要了解其工作原理,可以绘制部分提交图。在这里,我们将development
和... <- o <- * <- o <- ... <- o <-- master
\
o <- o <- ... <- o <-- development
作为两个分支提示,两个分支结构(提交链)最终连接起来:
*
标记为development
的提交是合并基础:它是master
和*
重新加入的点,并且提交merge
并且每个早期提交都在两个分支,而不仅仅是一个分支。
此时*
所做的是生成两个差异:一个从master
到当前提交的提示(*
上的提示提交),另一个来自{{ 1}}到另一个,目标,提交(development
的提示)。
在master
中,您有*
后的一些(可能不是太多)更改,而在development
中您有一些更改,包括添加Assets/Development/
。
merge
命令组合了这些更改,包括添加不需要的目录。完成所有操作后,git会进行新的提交(--no-ff
步骤保证这一点;如果合并基础提交*
是master
的提示,这不是我们绘制的但可能在第一次合并时,git会尝试快速执行标签而不是进行实际合并。
结果是一个现在看起来更像是这样的图形(我将停止在左箭头中绘图,只要知道历史向左移动,即稍后提交指回早期的箭头):
...--o--*--o-...-o---o <-- master
\ /
o--o-...-o <-- development
现在,您继续在development
上开发,进行更多新提交。我们将*
替换为o
,因为它不再是特殊情况。
...--o--o--o-...-o---o <-- master
\ /
o--o-...-o--o--o <-- development
并且在某些时候您决定再次合并,因此您检查master
并告诉git merge
找到development
的(新)提示并计算合并基数。
合并基础是(并且有点松散),两个分支上的第一个提交。让我们找到它:它和以前一样吗?从master
和development
的提示开始,从每个着色节点向后工作,使用两种不同的颜色。一旦节点获得两种颜色,这就是共同的祖先。最靠近提示的是&#34;最低&#34;,即合并基础。
我无法画出颜色,但如果你自己做这个练习,你会发现它是这个节点:
...--o--o--o-...-o---o <-- master
\ /
o--o-...-*--o--o <-- development
现在标记为*
的节点可以从master
(通过跟随第二个父级左下)和development
(通过链左侧)到达。它是最接近的节点,因此它是合并基础。
Git现在将合并基础*
与两个提示区分开来。如果对master
的提示进行任何更改(基本上只有从先前的合并基础和o
的新提示之间的master
节点中获取的任何内容)应该很少,以及自上次合并以来您对development
分支所做的更改。
如果这些更改影响Assets/Development
中的现有文件,则这些更改将导致合并冲突:
CONFLICT (modify/delete): Assets/Development/foo deleted in HEAD
and modified in development. Version development of
Assets/Development/foo left in tree.
Automatic merge failed; fix conflicts and then commit the result.
请注意,您不需要--no-commit
。
如果这些更改在Assets/Development/
中添加 new 文件,另一方面,merge会很乐意将它们添加到您即将进行的提交中,因此您需要{{1}避免添加任何此类文件。
如有必要,您可以再次使用--no-commit
来删除任何冲突和/或添加的文件。