假设我有一个我在git
中意外忘记跟踪的文件,例如Foo.sh
。在开发一段时间后,我意识到我需要git
跟踪此文件。
但是,由于该文件到目前为止还未被跟踪,如果我将其添加到特定分支Branch1
并进行提交,那么当我签出另一个分支时它将消失。
我目前解决此问题的方法是
Foo.sh
提交到Branch1
。Branch1
以外的每个分支,并执行git checkout Branch1 -- Foo.sh
。git commit -m "Added Foo.sh"
以外的每个分支上执行Branch1
。是否有更直接的方法来解决这个问题,假设我不介意每个分支上的提交消息是否相同?
答案 0 :(得分:1)
你需要樱桃挑选命令
$ git add file
$ git commit -m 'file added'
制作git log以查看提交的哈希值
$ git checkout another_branch
$ git cherry-pick 'hash'
$ git checkout another_branch2
$ git cherry-pick 'hash'
答案 1 :(得分:1)
Vlad Nikitin's method可以使用,虽然您可以通过分支名称识别提交樱桃选择来简化它:
$ git checkout branch1
... add and commit file ...
... at this point, "git show" will show that there's just the one change,
which is to add Foo.sh ...
$ for b in branch2 branch3 branch4; do
> git checkout $b && git cherry-pick branch1
> done
由于这是任何列出的分支上都没有的新文件,因此此处不应存在冲突。
如果(这是一个非常大的,如果)你没有发布任何新的提交,你可能想要“重写你的历史”一点,在分支出现之前,让它看起来像你之前放的Foo.sh
:
A---B---C---D <-- branch1
|\
| E <-- branch2
\
F---G <-- branch3
如果您可以修改提交B
以包含新的Foo.sh
,则“{1}}之后的所有提交也将包含B
。
您实际上无法修改Foo.sh
,但可以进行新提交,B
,这就像{{1}除了还添加B'
“之外。然后,您可以将B
通过Foo.sh
复制到新提交C
到G
,并将其基于C'
。为此,我将通过hash-ID检查提交G'
以获取“分离的HEAD”,添加文件并执行B'
:
B
现在为了方便和保护,我想要一个新的git commit --amend
提交的临时名称,所以:
$ git checkout 1234567
... git warns about detached HEAD ...
... create Foo.sh, make sure it's right ...
$ git add Foo.sh
$ git commit --amend
... editor ...
[detached HEAD 278c036] ...
N files changed, NN insertions(+)
create mode 100755 Foo.sh
create mode 100644 blah.txt
...
我刚刚意识到我不想输入B'
的哈希值,所以:
$ git tag temp_new_base
(我应该在B
之前完成此操作,但我忘了,所以我在这里做了,而是再次给出哈希ID。)
以下是我现在的照片:
$ git tag temp_old_base 1234567
现在所有 1 我需要做的是将三个分支中每一个的“git commit --amend
”链之后的每一个链接到新的 ____----temp_old_base
.
A---B---C---D <-- branch1
| |\
| | E <-- branch2
\ \
\ F---G <-- branch3
\
B'
.____
----temp_new_base
提交。这就是我刚添加的标签所在的位置:
B
这会复制B'
和$ git checkout branch1
$ git rebase --onto temp_new_base temp_old_base..
以进行提交C
和D
,并将其附加到提交C'
。这里的两个技巧是使用D'
,告诉rebase从commit B'
开始增长新的提交链;并使用--onto temp_new_base
,这意味着B'
,这意味着“temp_old_base..
上的所有内容都不在temp_old_base..HEAD
上”,这意味着提交HEAD
和{{1}在这种情况下。
当rebase完成时,我只需要重复剩下的两个分支:
temp_old_base
这一次,C
是D
,用于标识提交$ git checkout branch2
$ git rebase --onto temp_new_base temp_old_base..
,因此HEAD
表示只提交提交branch2
。
最后,我必须为E
重复此操作,之后我可以temp_old_base..
这两个临时标记。
(事实上,由于所有三个原始分支都来自同一个点 - 提交E
,我标记为branch3
- 并且git tag -d
命令对于所有三个都是相同的,我可以使用rebase命令执行相同的B
循环,这次 - 在每个分支的末尾挑选temp_old_base
。这一切都取决于我知道所有的分支“脱离rebase
”。)
1 “哈!全部!所有,他说!”但说真的,这实际上很容易。困难的部分是确定“滑入”for b in branch1 branch2 branch3; do ...
的点,并确保没有发布任何提交。如果他们 已发布,请不要这样做。 (好吧,除非你真的知道你在做什么,否则不要这样做,以上所有内容对你来说都是显而易见的,因为你必须帮助所有参与已发布提交的人,从中恢复此。)