6

I am experiencing a wild issue. I have my entire project in the master branch. Earlier, one guy was working on this project, but it was in SVN. He made some changes and I need to integrate those changes with mine. Both projects have the same folder structure, the only difference is the type of VCS used. I did the following

  • Downloaded his code and removed .svn folder
  • Created and switched to a new branch "code_to_integrate"(Points to my master branch)
  • Copied the downloaded code and replaced my project folder with it.(.git folder is kept as such)

At this stage, If I run git status command, I can see the changes(files are marked as modified) I need to integrate with my master branch. Then,

  • Committed those changes there.Let its commit id be c2
  • Checked out to my master branch.(commit id c1)
  • Merged it with "code_to_integrate" branch.

The result was that my code in the master branch overwritten with the code in the "code_to_integrate" branch. I lost my entire modifications. The HEAD is at c2 and I can see c1 as well. If I use

git reset --hard c1,

I will get back my changes. Right now, its like using the command

git merge -s theirs

I got the entire changes from the merging branch(code_to_integrate) and lost changes in merged branch(master). Whats happening?. This should be really straight forward right?. Any help will be appreciated. Thanks in advance

Shibin
  • 248
  • 1
  • 11
  • Could you please format / markup the question to be more readable? My eyes bleed and I can't mark it up properly (afraid to change the main question you have here in this post). – bahrep Jun 30 '14 at 13:14
  • I have formatted the question – Shibin Jul 01 '14 at 12:04
  • 1
    Try rebasing your `code_to_integrate` branch over `master`. Then merge the `code_to_integrate` branch into `master`. Git tries to find a common commit before attempting a merge(it may be finding a commit where the changes in `master` that you require are absent). IMHO always **rebase** your changes over the branch you wanna merge to before merging. – Shyam K Jul 01 '14 at 12:25
  • No use, shyam. Its getting overwritten. Anyway, thanks :) – Shibin Jul 02 '14 at 05:35
  • How was your master branch (and your git repository) created? is it converted from the SVN repo? If so, how did you convert it to git? just one initial commit (from some svn revision) ? or using `git svn clone`. A good answer highly depends on this. – Jarl Jul 02 '14 at 07:28
  • @Jari, I have created my repo in codebase and cloned it to my local machine. Then I copied the code to cloned folder. I then added the files, committed and pushed it back to codebase. – Shibin Jul 02 '14 at 07:42
  • @ShyamK, I think this is really bad advice. If you have a very divergent history rebasing will give you much more conflicts, as you have to resolve the conflicts on a commit level. Also it will change your history, thus messing with everyone's repository if you have already pushed your branch, and finally it will masking the fact that there was a huge branch/divergence in the first place. People should _not_ use rebase to avoid three-way merges, especially if there are conflicts to be resolved! – Robert Rüger Jul 02 '14 at 13:54
  • @RobertRüger Yes. I agree. YOU SHOULD NEVER REBASE PUSHED CODE. Just as people say don't mess with time travel, the same goes for pushed code. Rebase local changes(your local branch) on top of a remote branch, then push your branch/merge your branch into the remote branch. Rebase is not a method to avoid merges. – Shyam K Jul 02 '14 at 17:44
  • @ShyamK, I think you should also not do any rebases with conflicts, see [this answer](http://stackoverflow.com/a/11219380/1746785). Anyway, rebase vs. merge is not really the point of this question. I don't even know what happens when you try rebasing within a linear history. It'll probably do a fast forward merge, which is _not_ what Shibin wants. – Robert Rüger Jul 02 '14 at 19:51
  • 1
    @Shibin, I need you to ellaborate on "I have created my repo in codebase", does that mean that you loged in to your former SVN server and made a `git init`, `git add .`, `git commit` in the SVN repository base? I need to know how your the git repo is related to your colleagues SVN repo. I assume that the project has started as SVN and ended up as git, but how? – Jarl Jul 03 '14 at 06:14
  • @RobertRüger I was using the merge workflow, but simply merging code has caused me to lose data on multiple occasions. My code would get thrown out and the branch that I merged from overwrites my changes. (Ppl would just make a large commit) No conflict... nothing... just git's magical interpretation that this is needed and this is not. Never had a problem with rebase... so far :) – Shyam K Jul 03 '14 at 07:58
  • @Jari The code in SVN was downloaded, removed all .svn folders. Then I created a new repo in codebase, like we create a new repo in github, took a clone of that repo, added downloaded code to it, committed and pushed back to codebase – Shibin Jul 03 '14 at 14:30

1 Answers1

1

The problem is that you created the code_to_integrate branch on top of you master branch. So things looked like this:

... -> oldercommit -> oldcommit -> c1 (master, code_to_integrate)

When you then committed the other guy's code to this branch you get a linear history:

... -> oldercommit -> oldcommit -> c1 (master) -> c2 (code_to_integrate)

When you now merged code_to_integrate into master git detected that c2 is just newer than c1 and did a so called fast forward merge, which basically means only changing the commit that master points to to c2. Imagine code_to_integrate was just a quick branch you yourself made to do some work on, e.g. fix a bug. Once you are done you would have the exact same history and a fast forward merge would be precisely what you want.

In order to fix you problem you need to tell git which of you old commits is the newest common ancestor of your and the other guy's work. Basically you need to tell git at which point in time the other guy branched off your master. You so that by checking which is newest commit that both you and the other guy have in your history and then starting the code_to_integrate branch there. Assuming that the other guy branched off at oldercommit, you would do a git checkout oldercommit followed by a git checkout -b code_to_integrate and should get something like this.

... -> oldercommit (code_to_integrate) -> oldcommit -> c1 (master)

Once you commit the other guy's version you get:

             -> c2 (code_to_integrate)
            /
... -> oldercommit -> oldcommit -> c1 (master)

When you now merge code_to_integrate into master, git will see that there is a divergent history and do a three-way merge (where oldercommit is the mergebase), prompting you to resolve any conflicts that might arise, etc. This is what you want!

So in summary you simply started your code_to_integrate branch from the wrong commit. There is no way git or any other version control system can do a merge without knowing what the mergebase is.

EDIT: If you did not share any changes with the other guy since you put the code into git, then your mergebase is the oldest commit in your history. The following should do what you want:

git checkout $(git rev-list --all | tail -n 1)
git checkout -b code_to_integrate
[ ... put the other guys code into your working directory and commit it ... ]
git checkout master
git merge code_to_integrate

The first command checks out the oldest commit in your history, which is the last one that you and the SVN guy have in common. The 2nd command creates the code_to_integrate branch at your oldest commit and switches to it. Then you throw the other guys code into your working directory and commit it to the code_to_integrate branch. Finally you switch back to your master branch and merge the other branch in.

Robert Rüger
  • 851
  • 9
  • 21
  • _italic"Imagine code_to_integrate was just a quick branch you yourself made to do some work on, e.g. fix a bug. Once you are done you would have the exact same history and a fast forward merge would be precisely what you want." Bu this wont happen If my working directory or staging area has uncommitted changes that conflict with the branch iam checking. is it? There are changes in same files at same portions in both branches. So there must be conflicts – Shibin Jul 03 '14 at 14:44
  • "the other guy branched off at oldercommit". He dint branch off from my master. The project was initially in svn. I downloaded the that project, created a repo in codebase, just like creating in github, cloned the repo, added the files, committed and pushed it back to codebase. In nutshell, I converted a project in SVN to a project in GIT. After this, the guy pushed some more changes to the project in SVN. I need to get that changes. I cannot do the same process mentioned above because there are changes in my version(GIT) as well. – Shibin Jul 03 '14 at 15:37
  • He never did a `git branch` but in effect he _did_ branch off your master when you took the code from SVN and put it into git. It is the same as if both of you had been using git and he had done a proper git branch off of your very first commit. As your very first commit seems to be the mergebase, I'll update my answer with the git commands that should give you the desired outcome. – Robert Rüger Jul 03 '14 at 17:10
  • Thanks a lot. I got what I want. :) You saved a lot of my time. What you said was correct, my merge base was my first commit. When I put "code_to_ integrate" branch point to it, everything went well :) – Shibin Jul 04 '14 at 05:59
  • Glad to hear you succeeded! By the way: You can visualize your repository as a graph using `git log --pretty=oneline --abbrev-commit --graph --decorate --branches --remotes --tags` (command line, you can make `git graph` as an alias for it) or gitk (graphical). I almost always use this instead of the regular `git log`, because it makes relations between your branches so much more obvious. Using this you would probably have seen that what you asked git to do was impossible ;-) ... – Robert Rüger Jul 04 '14 at 07:03
  • Thanks Robert. I will surely look into it. By the way, you know any good tutorials about GIT, both advanced and basics?. Something you recommend? – Shibin Jul 04 '14 at 07:39
  • I think the book "Pro Git" by Scott Chacon is quite nice. It's also available on the git website: http://git-scm.com/book – Robert Rüger Jul 04 '14 at 13:14