我有一个包含html和javascript代码的分支。出于横切原因,我需要首先向html提交质量更改,然后再提交js。目前,我有一个分支,对其进行了两种更改。
如何按文件类型将提交分为两个较小的提交(或分支)?
答案 0 :(得分:3)
您无法更改现有提交,但可以进行新提交,其父级与现有提交的提交相同#34;提交太多"提交。
在开始之前,请确保您有一个干净的工作树("无需承诺")。那样没有git reset
或任何东西都可能失去任何东西。如有必要,您可以进行新的提交,以便您可能需要zorg~2
而不是zorg~1
(请参见下图)。您稍后可以从此提交中检索已保存的项目。
与Git一样,首先绘制(至少部分)你的提交图。你现在在某个分支上,这意味着你有分支 name 指向最尖端的提交,并且该提交指向一些父提交,依此类推:
...--A--B--C--D <-- zorg
其中zorg
是您当前的分支,大概是D
这是太大的提交而C
是它之前没有任何更改集的提交。 (如果你不得不再做一些提交,或许提交D
是一步或多步;如果是,请调整下面的数字。)
提示:使用git log --graph --oneline --decorate
(有或没有--all
)让Git为你绘制图形(虽然它垂直绘制,顶部有更多近期的东西,而不是水平向右边的新东西。)
您无法更改D
,但可以进行新的提交E
和F
,您可以这样安排:
...--A--B--C--D <-- ... we'll fill this in later ...
\
E--F <-- ... likewise this ...
或者这样:
F <-- ...
/
...--A--B--C--D <-- ...
\
E <-- ...
提交D
将继续成为您的&#34;太大&#34;提交虽然E
可能只有HTML更改而F
可能只有JS更改。 (如果F
构建在E
上,那么它确实有两个更改,实际上就内容而言提交D
。如果F
构建在C
上然后它只有 JS的变化。由你来决定如何安排这些。)
每个...
都要用分支名称填写。您可以单独保留现有的分支名称,并创建一个或两个新的分支名称,这是我首先显示的名称。
我们假设您想要两个新的分支名称,E
和F
各自拥有C
作为其父级(因此,不是 C--E--F
)。 Git是Git,有很多方法可以做到这一点,但一个简单的方法就是使用git checkout -b
创建它们,这会创建新的分支名称并切换到它们(以便git status
说你&#39} ;重新开始新的分支)。此git checkout -b
命令还采用可选的提交说明符,这是在创建新分支后在索引和工作树中具有的提交。我们希望E
和F
都来自C
,因此我们希望创建新的分支&#34; at&#34;提交C
:
git checkout -b zorg-html zorg~1
名称zorg
标识提交D
。添加~
后缀意味着来自此提交的#34;退回到第一个父链接,但是我多次在数字&#34;中说。由于该数字是1(一),我们将退回一个父母,这将我们从D
带到C
。这意味着名称zorg-html
目前将指向提交C
,我们将在此新分支上。
现在我们已经zorg-html
(在提交C
),我们只想替换所有HTML文件。这些文件的正确版本位于提交D
中,如名称zorg
所指向的那样。获取这些文件的简单方法是:
git checkout zorg -- first_file second_file third_file ...
这对git checkout
有点疯狂 - 这次根本不会更改分支,而只是提取特定的命名文件(文件名列表)来自指定提交(--
的{{1}}部分之后),即提交zorg
)。
如果这些文件都以D
结尾,而且.html
文件实际上不是HTML文件,这种简单方法的简单版本是:
.html
也就是说,从顶级目录中获取名为git checkout zorg -- '*.html' '**/*.html'
的每个文件,并从whatever.html
提交中提取任意数量的子目录中名为whatever.html
的每个文件(提交) zorg
,再次)。
这种D
将更新的文件写入索引和工作树,因此此时您只需git checkout
结果。
现在,要创建提交git commit
,我们重复整个过程:
F
(假设,与之前的HTML文件一样,每个JS文件都被命名为git checkout -b zorg-js zorg~1 # new zorg-js branch starting at C
git checkout zorg -- '*.js' '**/*.js'
git commit
,而没有名为.js
的文件是其他而不是JS文件。现在我们有:
.js
显然,您可以为所有这些分支选择更好的名称。
如果您希望在提交 F <-- zorg-js
/
...--A--B--C--D <-- zorg
\
E <-- zorg-html
之后进行提交F
,只需省略将创建新分支的E
并切换回提交git checkout -b
。当您提取所有C
文件并生成提交zorg-html
时,这将使您在提交E
的分支.js
上,以便F
&#39; s父母将是F
,您将拥有:
E
如果你想要的只是一些简单的食谱,你可以在这里停下来。如果您想学习很多方法来解决这个问题和其他问题,请继续阅读。
...--A--B--C--D <-- zorg
\
E--F <-- zorg-html # zorg-html is clearly a bad name
本身E--F
怎么办?没问题。 Git是Git,有多种方法可以做到这一点。例如,您可以在开始之前重命名zorg
:
zorg
现在你有了这个:
git branch -m zorg gary-oldman
您可以安全地创建新的A--B--C--D <-- gary-oldman
。
当然,任何上游设置都坚持使用重命名的分支。没什么大不了的,您可以使用zorg
为每个分支设置新的上游。
当然,Git是Git,还有另外一种方法!您可以创建一个新的分支名称 now ,指向提交git branch --set-upstream-to
,只要您需要它就可以记住它 - 您需要它来为两个{{1} }命令。然后,您可以D
分支名称git checkout
,以便它指向提交git reset
:
zorg
现在,当您进行新的提交时,他们会将名称C
向前移动,但名称git checkout zorg # make sure zorg is the current branch
git branch temp # save its tip commit under a new name
git reset --hard zorg~1 # and move zorg back to commit C
仍将为您记住提交zorg
:
temp
现在要访问提交D
,您将使用名称A--B--C--D <-- temp
\
E <-- zorg
,并重新查找提交D
,您将使用temp
。
请注意,如果您有额外的提交&#34;过去&#34; C
(例如,用于保存HTML和JS更改后完成的工作):
temp~1
你仍然可以做到这一切。它就是现在,要命名提交D
,您将需要其SHA-1哈希&#34;真名称&#34; (这永远不会改变,但真的难以正确输入 - 鼠标剪切和粘贴在这里很有帮助),或从小费倒计时。此处A--B--C--D--H--I--J <-- temp, or zorg, or whatever
可能将提交命名为C
,temp
提交J
,temp~1
为I
;因此,temp~2
为H
,temp~3
为D
。一旦你完成了分割提交,你就可以挑选剩余的提交。
temp~4
Git是Git,还有另一种方法可以做到这一点,如果在C
之后提交,则提交拆分尤其有用。这个特别的需要Git的一些安慰,但最终是最短和最快的方法。我们从git rebase -i
开始将提交D
(以及任何后来的提交)重新绑定到git rebase -i
,它已经(或者它们已经存在);但我们将D
的{{1}}行更改为C
。
Git现在让我们进入了已经提交了pick
的rebase会话。现在我们想要D
(或edit
; D
只是默认值)返回提交git reset HEAD~1
。这将设置当前提交 - 我们处于分离的HEAD模式,因此这只是将git reset --mixed HEAD~1
本身调整为--mixed
并重置索引以匹配C
,但保留了工作 - 树设置为HEAD
。现在我们只选择C
我们想要的文件:所有C
个文件。使用您喜欢的任何方法(例如D
或git add
)添加这些方法,并.html
结果。然后find ... | xargs git add
剩下的文件再次git add '*.html' '**/*.html'
,然后再git commit
复制剩余的提交,并将分支标签移动到最末端的提交。
答案 1 :(得分:0)
我从this answer:
一起攻击了它git checkout -b new-branch # checkout from master
git diff big-branch --name-only -- '*.html' | xargs git checkout html-comments-take-two --
如果文件名中有空格,可能需要传递给sed 's, ,\\&,g'
。
我无法使用**/*.html
样式路径规范让它工作,我不知道为什么。