user1030151
user1030151

Reputation: 407

Change Git master branch path?

I would like to change the path of the master branch. I don't know how to describe it, so here is an image which shows what I mean. On the left side you see the current state and on the right side you see the desired state:

So, while there are two paths, the one commit in the master brach should be in the side branch and vice versa. Is there a way to do that?

Upvotes: 0

Views: 1327

Answers (2)

torek
torek

Reputation: 489828

As evolutionxbox commented, you cannot always trust the coloring provided by graph-viewers (how much to trust depends on the specific viewer). However, Git itself does give some significance to some paths through the graph.

The commit graph, like any graph, can be defined as G = (V, E) where G is the graph and V and E are the vertex (or node) set and edge set respectively. In this particular mathematical formation, all edges are equal: it does not matter if you go from a merge commit whose node ID is c123456 backwards through its first parent edge to commit a000000 or through its second parent edge to commit b000000. But to Git, the --first-parent flag to git log will trim away all merge-commit edges that are not the first commit.

That is, the mathematical properties of the graph are not dependent on path order, and most parts of Git descend both paths simultaneously, but for some purposes, especially including git log --first-parent, you may really want to control which parent is the first parent, and which is the second.

Unfortunately, once a merge commit is made, it cannot be changed. No commit can ever be changed; no power on earth can do that.

What you can do is make a new merge, in the other order, so that the first parent of the new merge is the node that is the second parent of the current merge, and that the second parent of the new merge is the first parent of the current merge. To do that in Git, check out the second parent—preferably while also attaching a new branch name to it—and run git merge ID-of-first-parent (note that you may use the two hash IDs directly, or any spelling as found in the gitrevisions documentation that finds them):

$ git checkout -b rework <ID of second parent>
$ git merge <ID of first parent>

Since you have at least three commits that come after the merge, you will need to copy those commits as well:

$ git cherry-pick <ID>..<ID>

If you do have uncommitted changes—the image above looks like gitk output, and gitk invents a fake commit-graph node for uncommitted changes—you can do all of this in a separate work-tree, or just commit the changes first, so that you have a clean tree in which to work.

Once you have built up this new graph segment on this new branch named rework, you can forcibly re-point the label master to point to the final such commit. This chain of commits, unlike the original chain, has a merge commit whose first parent is the commit you want as its first parent. That is, the two parents are reversed. This is because the first parent of any merge commit is always the commit that was HEAD at the time you ran git merge. Assuming you have built the new chain and are happy with it, and are still on the rework branch:

git branch -f master rework

or:

git checkout master && git reset --hard rework

Note that this kind of reworking of commits assumes you have not delivered the merge commit and the subsequent commits to any other Git repository, or that if you have, everyone else who uses that other repository is OK with having master change in an unusual fashion.

Note, too, that git pull makes these kinds of "reversed" merges (well, reversed from one particular point of view; from another rather narcissistic viewpoint, they're entirely correct!). Some call this a foxtrot merge. If you have control over a pre-receive or update hook on the server, you can forbid them. As a user, you can avoid using git pull. (I recommend avoiding git pull in general: it's a convenience command that is, well, inconvenient.)

Upvotes: 1

hong4rc
hong4rc

Reputation: 4113

Try rename of branch :

git branch -m master new-name
git branch -m old-name master

And if you want swap name:

git branch -m master temp-name
git branch -m old-name master
git branch -m temp-name old-name

Upvotes: 1

Related Questions