git commit to all branches

给你一囗甜甜゛ 提交于 2019-12-17 16:18:51

问题


If I fixed a bug in a file in branch branch_a, which should be applied to all branches. Is there a way to apply the change to all branches without having to checkout the branches individually.

git commit -m 'commit msg' # on branch a 

git checkout branch_b
git cherry-pick branch_a

git checkout branch_c
git cherry-pick branch_a

What i would like to have is a git commit --to-all-branches which tries to propagate the changes to all branches if possible.

Edit

To clarify a bit my situation, I write code to for computational problems. Often I end up in the situation where it is unclear which approach is the best solve a given problem. So i create a branch. These branches tend to diverge and are more like forks. However to keep all the files in place I just use one git repository with multiple branches. In the situation of a bug relevant for all branches/forks I was looking for away to update all branches automatically.


回答1:


No—or strictly speaking, "yes, but it's just as much work any other way". New commits are always added to "the current branch", even if that's a "detached HEAD". (Below, I'll show a way of doing this with the "detached HEAD" state, although if you're adding commits to existing branch-tips, that's more work than just checking them out.)

Assuming you have something like this:

A-B-C          <-- br1
   \
    D   F      <-- br2
     \ /
      E
       \
        G      <-- br3

and you have some fix X that must be applied on top of C, F, and G to give:

A-B-C-X1       <-- br1
   \
    D   F-X2   <-- br2
     \ /
      E
       \
        G-X3   <-- br3

(note that all 3 Xn commits are different commits as they have different parents), then you must add "patch X" to commit C, and then add "patch X" to commit F, and then add "patch X" to commit G.

Note that there is no guarantee that, e.g., the change from C to X1 exactly matches the change from F to X2 here, either. You may construct any of the three Xn commits first, in the usual way. Then (as in your question) you just move to the other branches and git cherry-pick to create (and possibly resolve conflicts in) the other X-es. But you need to be "on" those branches to add commits to them, so:

$ git checkout br1
... make fix, "git add", "git commit" to create X1

$ git checkout br2
Switched to branch 'br2'.
$ git cherry-pick br1    # take diff of `C`-vs-`X1`, apply to `F` to make `X2`
... etc

Repeat for all branches to which the patch must be copied (and, if necessary, modified to fit that branch).


There are alternatives to doing this. For instance, suppose branch br1 is actually OK, and what you've discovered is that commit E is broken and needs to be fixed, affecting commits F and G. Suppose further that either no one else has commits F and G—or, you're willing to force those who do have those two commits, to do a bunch of work to recover from what you are about to do. In that case, you can check out commit D and make a new commit, E', that comes off of D. Let's draw the starting point, leaving out A through C. We'll git checkout D (by its SHA-1, or—equivalently with this graph—by using br2~2 to name it) to get a "detached HEAD" there:

D       <-- HEAD
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

Now:

$ git cherry-pick -n br2^  # make a copy of E but don't commit yet
# edit to fix it
$ git commit               # make new commit E' that's fixed

Once the commit finishes, we have this (still with the "detached HEAD):

  E'    <-- HEAD
 /
|
|
D
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

Now we can copy commit F to F':

$ git cherry-pick br2

giving:

    F'  <-- HEAD
   /
  E'
 /
|
|
D
|
|   F   <-- br2
 \ /
  E
   \
    G   <-- br3

We're now ready to make br2 refer to commit F':

$ git branch -f br2 HEAD

giving:

    F'  <-- HEAD, br2
   /
  E'
 /
|
|
D
|
|   F   [abandoned]
 \ /
  E
   \
    G   <-- br3

(This is the "or strictly speaking" part I wrote above: you can add commits to a repository, then move branch labels around so that they label the new commit chains, rather than their old ones. All added commits move HEAD: it's just that if HEAD is a reference to a branch, they also move the branch one step forward as you work. Having HEAD refer to a branch is the "normal" way of working, but you can fake it after-the-fact in "detached HEAD" mode with git branch -f. In this case, I'm doing that to build the new br2 without using a branch name, then moving the branch name to the new chain of commits once it's ready.)

Now we need to copy G to G', attaching G' to E'. Here are the steps:

$ git checkout br2^      # get back on E' as a detached HEAD
[git says stuff here about moving the detached HEAD]
$ git cherry-pick br3    # copy commit G
$ git branch -f br3 HEAD # and move br3 label here

(this is what we did for copying F to F', more or less) giving:

    F'  <-- br2
   /
  E'
 / \
|   G'  <-- HEAD, br3
|
D
|
|   F   [abandoned]
 \ /
  E
   \
    G   [abandoned]

Once you're all done, you should probably git checkout somebranch to get back "on a branch", and away from this "detached HEAD" state.

As noted in comments, needing to apply a patch as wide-spread-ly (is that a word?) as this suggests that maybe there's something wrong with the whole process. (But this is what fixing a "day zero bug" looks like when you have a bunch of different products that all share the code-base with the day-zero bug.)




回答2:


This doesn't exist, because each merge can potentially result in separate conflicts that require user intervention. You would need to write a script to do what you want.



来源:https://stackoverflow.com/questions/21459976/git-commit-to-all-branches

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!