0

I have a case where history of the library upon which I made my work, and of my work have diverged. Some time after I branched off of the original branch that contains library 1.0, the library's developer released an update, which I need to incorporate into the end result, keeping my changes that were made on top of that.

There is already an answer to a similar question here. However, many experienced Git users do not recommend rebasing commits that are already public, and for a good reason: the history will be re-written. Anything attached to the previous commits will be lost. Keeping pull requests for "book-keeping" will become useless. So, what is the best approach if I want to achieve a similar result, but keep the history sane, and, more importantly, have the local repositories of collaborators consistent?

I expect that the developer of the underlying library will make new releases once in a while, and this process needs to be repeated every time, with all the drawbacks. The graph would look something like this:

product ------P1--P2--P3--P4'--P5--P6'
             /           /        /
library ---L1----------L2-------L3

Anyone?

Community
  • 1
  • 1
XedinUnknown
  • 677
  • 9
  • 25
  • The solution that seems to be working so far is: creating a temporary branch off of `product`, called `integration`, rebasing it onto `library`, and then merging `integration` into `product`. – XedinUnknown Jul 07 '15 at 22:30
  • Oops, this results in the new commits of the `integration` branch, that are the result of the rebase, to be repeated again on `product` – XedinUnknown Jul 07 '15 at 22:40

2 Answers2

0

Use git merge instead of git rebase. This will create a "merge commit" rather than re-writing history.

For example:

git fetch
git merge library/master
mkasberg
  • 16,022
  • 3
  • 42
  • 46
  • I understand that the merge will overwrite the changes that I made to the library. No? – XedinUnknown Jul 07 '15 at 22:29
  • No, it shouldn't. What makes you think so? – mkasberg Jul 07 '15 at 22:30
  • 1
    Let's say, you create a file, and commit it (A). Then, you delete that file, and commit that (B). Then, you merge a branch, which has that file, into your head, which is at B. The file will be created again. That's what logic tells me. – XedinUnknown Jul 07 '15 at 22:35
  • The file will not be created again. Git is smarter than that. It knows you want your own changes to remain in your branch. But if the file was changed in the other branch since the branches diverged, there would be a merge conflict (which you could resolve by deleting the file). This is the same behavior as rebase. Try it: `cd test`, `echo foo > a.txt`, `git init`, `git add a.txt`, `git commit`, `git branch library`, `git rm a.txt`, `git commit`, `git merge library`. Git says `Already up-to-date.` The file is not created again. – mkasberg Jul 08 '15 at 00:24
  • That's probably because they have a common ancestor, and the branch in the library doesn't get added again. In your case, the `library` branch has a history, and that history doesn't say "add file again". In my case, the library is maintained by someone else separately from me; new versions come as one whole commits every time. What about the solution I describe in my answer? – XedinUnknown Jul 08 '15 at 10:08
  • The integration branch in your answer is useless. It is just extra commands with the same end result. I don't understand your objections to my answer. As long as you have the library set up as a remote branch, the behavior will be the same. – mkasberg Jul 08 '15 at 17:26
  • How is the result the same? In my case, you re-play your own changes on top of an updated library, and then create a commit with what changed in your own branch. In your case, you apply the changes in the library on top of your own changes, on top of the library. The description includes a link to another question, the answers to which describe "Why rebase?". – XedinUnknown Jul 13 '15 at 09:47
  • The result is the same because in both cases the P4 commit contains everything that changed between L1 and L2. The part of your comment discussing how the changes are applied doesn't make sense to me. The question you linked does not answer "Why rebase?". It says that rebasing is one possible solution to the problem discussed. But you said you don't want to rebase because you don't want to re-write history, so I proposed a solution that does not involve rebasing. Did you even try my suggestion? If you're afraid it will bork your repository, try it on a separate clone first. – mkasberg Jul 14 '15 at 00:13
  • I didn't say I don't want to rebase. I want the benefits of rebase, but still keeping linear, consistent history for all who work on the main branch. Your suggestion does not have the benefits of rebase, because it is not a rebase. But mine does. Don't you think? – XedinUnknown Jul 14 '15 at 10:56
  • Specifically which "benefits of rebase" are you talking about? You don't seem to know what your goal is. You said in your original post, "many experienced Git users do not recommend rebasing commits that are already public, and for a good reason: the history will be re-written," implying that you don't want to rebase. Your original concern with the above answer was that it will overwrite your changes, which it in fact will not. So I don't understand what you're trying to do that a merge does not achieve. – mkasberg Jul 14 '15 at 14:23
0

The answer I found is by using rebase, then merge. The rebase is done on a temporary branch.

product         P1--P2--P3------P4--P5--P6--P7------P8---
               /        |      /            |      /
integration   /         P3--P3'             P7--P7'
             /             /                   /
library ---L1------------L2------------------L3---

This can be achieved like so:

$ git checkout library
$ git fetch --no-tags library master
$ git merge library/master
$ git checkout -b integration
$ git rebase library
$ git checkout product 
$ git merge --squash integration
$ git branch -D integraton
XedinUnknown
  • 677
  • 9
  • 25