【问题标题】:Is there a way to add a single file to multiple (local) branches at once?有没有办法一次将单个文件添加到多个(本地)分支?
【发布时间】:2014-02-01 06:25:04
【问题描述】:

假设我有一个不小心忘记在git 中跟踪的文件,例如Foo.sh。经过一段时间的开发,我意识到我需要这个文件被git跟踪。

但是,由于该文件到目前为止还没有被跟踪,如果我将它添加到特定分支 Branch1 并提交,那么当我检查另一个分支时它会消失。

我目前对这个问题的解决方案是

  1. Foo.sh 提交到Branch1
  2. 检查除Branch1 之外的每个分支,然后执行git checkout Branch1 -- Foo.sh
  3. 在除Branch1 之外的每个分支上执行git commit -m "Added Foo.sh"

假设我不介意提交消息在每个分支上是否相同,是否有更直接的方法来解决此问题?

【问题讨论】:

标签: git version-control dvcs


【解决方案1】:

Vlad Nikitin's method 可以工作,尽管您可以通过分支名称识别对 cherry-pick 的提交来简化它:

$ 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

由于这是一个没有出现在任何列出的分支上的新文件,所以这里应该没有冲突。


如果(这是一个非常大的if)您还没有发布任何新的提交,但是,您可能想要“重写您的历史”一点,让它看起来像你在分支分歧之前把 Foo.sh 放在前面:

A---B---C---D   <-- branch1
     |\
     |  E       <-- branch2
      \
        F---G   <-- branch3

如果您可以修改提交B 以包含新的Foo.sh,那么所有“之后”的提交B 也将包含Foo.sh

你实际上不能修改B,但是你可以做出一个提交,B',那是“就像B除了还添加@ 987654332@"。然后你可以将CG 复制到新的提交C'G',基于B'。为此,我会通过哈希 ID 检查提交 B 以获得“分离的 HEAD”,添加文件,然后执行 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 的哈希值,所以:

$ git tag temp_old_base 1234567

(我应该在 git commit --amend 之前完成此操作,但我忘记了,所以我在这里通过再次提供哈希 ID 来代替。)

这是我现在的图片:

     ____----temp_old_base
    .
A---B---C---D   <-- branch1
|    |\
|    |  E       <-- branch2
 \    \
  \     F---G   <-- branch3
   \
    B'
     .____
          ----temp_new_base

现在所有1 我需要做的是将三个分支中每个“B”之后的每个链重新设置为新的B' 提交。这是我刚刚添加的标签的来源:

$ git checkout branch1
$ git rebase --onto temp_new_base temp_old_base..

这将复制CD 以提交C'D',并将它们附加到提交B'。这里的两个技巧是使用--onto temp_new_base,告诉rebase 从提交B' 开始增长新的提交链;并使用temp_old_base..,表示temp_old_base..HEAD,表示“HEAD 上的所有内容,temp_old_base 上也不存在”,这表示在这种情况下提交CD

当那个变基完成时,我只需要对剩下的两个分支重复:

$ git checkout branch2
$ git rebase --onto temp_new_base temp_old_base..

这一次,HEADbranch2,它标识了提交E,所以temp_old_base.. 意味着rebase 只是提交E

最后,我必须对branch3 重复此操作,之后我可以git tag -d 这两个临时标签。

(事实上,由于所有三个原始分支都从同一点增长——提交B,我将其标记为temp_old_base——并且rebase 命令对所有三个都是相同的,我可以做同样的@ 987654374@ 循环——这次用 rebase 命令代替——至于樱桃采摘Foo.sh 到每个分支的末尾。这完全取决于我知道所有分支“来自B”的事实。 )


1“哈!全部!全部,他说!”说真的,这实际上是最容易的部分。困难的部分是确定“滑入”Foo.sh 的点,并确保从那里开始的任何提交都不会被发布。如果它们发布,请不要这样做。 (好吧,除非您真的知道自己在做什么,否则不要这样做,并且以上所有内容对您来说都是显而易见的,因为您必须帮助所有接受已发布提交的人,从这个。)

【讨论】:

    【解决方案2】:

    你需要chery-pick命令

    $ 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'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多