Is it possible to rewrite the history of branches without losing information about merging along the way?

We have a leading branch into which we have combined about 10 function branches one at a time.

So, a recent story looks like this:

merged feat/10 (HEAD of master) merged feat/9 merged feat/8 merged feat/7 merged feat/6 merged feat/5 ... 

Now we found out that feat/7 was bad and we want to get it out of the wizard. The return of this merger is not enough, because we do not want this violation to be recorded in our history in general. We cannot use interactive rebase because it will smooth out the story so that it looks like everything was done in one branch, and we want to keep everything thatโ€™s a good merge story.

Is there a way to block a specific merge commit from branch history?

I note that the real story is much more complicated than what you see in the above example, so manually repeat all the merges, since feat / 7 would not be a good option.

Edit

To clarify to those who vote to close this as duplicate: this is not a FAQ on how to infer a commit with rebase, which of course has been answered many times. The question here is to take out the fix without smoothing the merger history.

+6
source share
4 answers

If your story currently looks like this and you are not deleting branches, but you can just git reset --hard HEAD~4 , it will reset when your code returns to the state before merging into 7, then you can just git merge good ones return to This is the easiest way that I can think of my head.

EDIT: You can use the -p switch for rebase to save merges, but using this switch with -i may have consequences. Check the man git -rebase page and see the BUGS part to see current errors.

EDIT2: I accept no responsibility unless you take proper precautions before using this command. Do not use it before reading the man page.

+1
source

You can use git filter-branch --parent-filter to rewrite the feat/8 commit so that its parent points to the feat/6 commit. Leaving the parents of all other commits (9-10), as they are, which should preserve the merge, are recorded in the history as they were.

The only problem with this is what happens to conflicts that cause the remote code to change ... there is no real way to find out, and that could be the culprit.

+1
source

This is not exactly what you want to do (the "zap" merge, so to speak), but in practice it is easier than convincing your co-authors to git reset --hard after rebase or filter-branch . Just return the merge.

 git revert -m 1 <commit_for_feat7> 

I donโ€™t particularly like polluting my revert master branches, but there is nothing wrong with that. If you are not going to fix feat7 for a while or just want its changes to go out of history, this solution is much less problem than revising history.

+1
source

You can't just pack stuff from git because the current hash depends on the whole story.

One option is to create a new branch that starts with feat / 6 and then has merges starting with feat / 8, so that the branch branch can point to another hash without changing from feat / 7.

Another option, if I'm not mistaken, is git replace (I think it was called transplants). It can let you "replace" the pointer with feat / 8 from feat / 7 to feat / 6. I'm not quite sure how exactly this is achieved, but it seems like this is not a real replacement, because feat / 8 still has a pointer somewhere feat / 7, because the hash does not change, but git replace somehow adds an alternative story in which feat / 8 points to feat / 6. On the man page:

 git replace [-f] <object> <replacement> git replace -d <object>โ€ฆ git replace -l [<pattern>] 

Adds a replacement link to .git / refs / replace /

The name of the replacement link is the SHA1 of the object that is being replaced. The content of the substitution reference is a SHA1 replacement object.

If -f is not specified, a replacement reference does not yet exist in .git / refs / replace /.

Replacement links will be used by default by all git commands, as well as those that bypass the target (cropping, packet transfer, and Fsck).

You can disable the use of replacement links for any using the -no-replace-objects option immediately after git.

EDIT: In a second thought, git replace might be a bad idea, since changes to feat / 7 will exist in the merge of feat / 8. You should probably just skip to the first option: start a new merge branch feat / 6 and remerge, starting with feat / 8

0
source

Source: https://habr.com/ru/post/922201/


All Articles