有没有办法一次将单个文件添加到多个(本地)分支?

时间:2014-02-01 06:25:05

标签: git version-control dvcs

假设我有一个我在git中意外忘记跟踪的文件,例如Foo.sh。在开发一段时间后,我意识到我需要git跟踪此文件。

但是,由于该文件到目前为止还未被跟踪,如果我将其添加到特定分支Branch1并进行提交,那么当我签出另一个分支时它将消失。

我目前解决此问题的方法是

  1. Foo.sh提交到Branch1
  2. 查看Branch1以外的每个分支,并执行git checkout Branch1 -- Foo.sh
  3. git commit -m "Added Foo.sh"以外的每个分支上执行Branch1
  4. 是否有更直接的方法来解决这个问题,假设我不介意每个分支上的提交消息是否相同?

2 个答案:

答案 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复制到新提交CG,并将其基于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.. 以进行提交CD,并将其附加到提交C'。这里的两个技巧是使用D',告诉rebase从commit B'开始增长新的提交链;并使用--onto temp_new_base,这意味着B',这意味着“temp_old_base..上的所有内容都不在temp_old_base..HEAD上”,这意味着提交HEAD和{{1}在这种情况下。

当rebase完成时,我只需要重复剩下的两个分支:

temp_old_base

这一次,CD,用于标识提交$ 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 ...的点,并确保没有发布任何提交。如果他们 已发布,请不要这样做。 (好吧,除非你真的知道你在做什么,否则不要这样做,以上所有内容对你来说都是显而易见的,因为你必须帮助所有参与已发布提交的人,从中恢复此。)