问题
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