1

Here's my history:

* 8 [mybranch, origin/mybranch] * 7 |\ | * 6 [master, origin/master] * | 5 * | 4 |/ * 3 * 2 * 1 

Since 3rd commit, a new branch was created, and after a few commits, I have merged my branch with the updated master (I should have rebase but I made a merge instead). So, to have a cleaner history, I want to achieve that (a linear history) :

* 8 [mybranch, origin/mybranch] * 7 * 6 [master, origin/master] * 5 * 4 * 3 * 2 * 1 

Is it possible ?

Thanks

3 Answers 3

2

You should be able to do that simply with:

$ git rebase master mybranch 

Rebasing flattens history by default, and the above incantation says to rebase everything in mybranch that is not yet in master on top of master. The result should look like this:

* 8' [mybranch] * 5' * 4' * 6 [master, origin/master] * 3 * 2 * 1 

This is not quite what you were asking for, but I think it is what you want. The master branch is preserved and only your mybranch history is affected.

Also note that commit 7 was lost in this process. Merge commits should not appear in a flattened history as they should not be introducing any changes themselves. This is true even for merges that require conflict resolution. By rebasing one branch on top of another, the conflicts will occur (and need to be resolved) in one or more of the rebased branch's commits. Effectively the work done previously by the merge commit is folded into the rebased commits.

Assuming mybranch is something not being used by others, I think doing this rebase in this case makes sense. But I agree with @amn: it's best to avoid mucking around with history too much. I think "more simplistic" is a better description of linear history than describing it as "cleaner", as I think the latter tends to imply merging is a less desirable workflow. Merging is more robust and much more scalable than rebasing. With the latter workflow, you really should build and test each rebased commit, whereas with a merge workflow you only need to test the final merge commit.

Sign up to request clarification or add additional context in comments.

Comments

0

You have to make a new history. The most direct way to create the history you wanted in the first place is

git rebase master mybranch 

It's not the history you created so far, it's a different one, so the id's on the new commits are all different, but it looks like

* 8' mybranch * 5' * 4' * 6 master origin/master * 3 * 2 * 1 

in your repo, with your origin/mybranch and the refs in every other repo that history was ever fetched or pushed into still referring to the old one you no longer love. If you've got good communications with everyone who's got a copy of that old history and they're fine doing a fetch and rebase to switch to the new one, git push -f origin mybranch is is by far the best way to handle this.

Getting as close as possible to the literal result you asked for, the 12345678 history, involves rewriting the master-branch history too, and producing a history you wouldn't have gotten if you'd done it right the first time.

Another option, especially if the existing mybranch history has found its way into repos you don't have much contact with, is to just leave it the way it is and carry on. Linearity is nice, but that's all it is.

2 Comments

Well done ! I've changed my mind for two reasons : modify pushed commits is very dangerous (mostly if structure changed) and rebased files do not reflect a code that existed -- (excuse my english if I'm not clear !)
The most direct command sequence is git rebase master mybranch.
-1

You cannot actually move commits with Git -- commit parentship is part of its identity -- once you re-parent a commit it's no longer the same commit, even if the set of changes it brings are the same. Git purposefully digests as much of a commit into its identity. This helps Git ensure the data integrity of the entire repository. See, corruption of a commit will invariably hash into another identifier which by design will ripple through the entire graph, as Git won't be able to resolve parent references and will basically tell you that the graph is corrupt.

Anyways, your commits 6, 7 and 8 will in any case not directly participate in the final graph as-is, but their equivalents (assuming you resolve potential merge conflicts during their creation) will be represented as 6', 7' and 8'.

What you need to do is "reparent" (in quotes because as described above, changing parent is no longer the same commit) commit 6, incidentally pointed to by the master branch, with:

git rebase 5 master 

The above creates an equivalent of changes introduced with commit 6 but as if these changes were applied on top of commit 5. This may or may not succeed without merge conflicts, which are entirely up to you to resolve by editing files with conflicting content areas.

You may try an interactive rebase (add the -i switch to the above command) to have full control, but I suspect that it won't be necessary in your case.

So, your commit 6 will stay as it is, but another commit, let's call it 6' will appear with 5 as sole parent -- the rebase product. Commits are shown by git log ordered by their timestamp by default, so expect to see 6' at the top of the graph/list.

In a similar fashion, you then rebase the commit pointed at by mybranch on top of that new commit 6', which is also your new master now:

git rebase master mybranch 

After you are done with both rebasing operations, you will have your desired graph of commits. Keep in mind though that because you are tracking the master branch on your "origin" repository (with origin/master), the commits referenced by that branch will remain, which may look confusing, but is necessary since after all git will be unable to synchronize the repositories otherwise.

I would also recommend you to not muck about with history too much. I know it looks confusing, but one thing you have got to keep in mind is that human work is often non-linear enough to actually produce the kind of graphs we then tend to find untidy. But the graphs only represent our work, and are not in themselves untidy. This particular bit is just my opinion, yours may differ.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.