Working Around Merge Conflicts In a Git Rebase

Sometimes you get merge conflicts when rebasing complicated repositories. It doesn’t always happen but it seems to be when existing conflicted merges are resolved. If you’re sure that your rebase doesn’t really conflict with anything in your repository, then you can tell the merge strategy to pick the new change using the following command:

git rebase -s recursive -X theirs master

This just picks the state in the new patch; in other words the diff will reflect the new changes plus any merge resolutions.

It’s still possible to see conflicts when files are deleted and modified in a merge conflict, however you can resolve this with git checkout --theirs FILE ; git add FILE.

I’m not completely sure on why this situation occurs. I think git is simply being safe about how it treats the patches in the history. What we’re doing here is pretending the merge solution never happened and that all commits played well with each other which is not the case in reality. Therefore this command is destroying the history of patches as they actually happened. I’m merging extremely old repositories that have very messy histories anyway so it’s difficult for me to assess the impact of this other than to say that the log looks OK and the files are as they should be.

If all you’re looking for is a nice output of git blame and a bisectable history then this method should be OK for you.

Advertisements
Working Around Merge Conflicts In a Git Rebase

Splitting Subsets of a Git Repository

Sometimes I need to split one or two useful files from a predominantly useless repository. This can be done with subtree merges and subdirectory filters, but if the files are not organised very well then this can prove difficult.

The following quick filter will get you just a few files, providing they don’t move around too much:

git filter-branch --index-filter \ 
  'git rm --cached -qr -- . && \ 
  git reset -q $GIT_COMMIT -- \ 
  FILENAME FILENAME2'

Note that I’m using index-filter rather than tree-filter.

We’re just deleting everything and then resetting the files we want all in one go.

As I wrote in my other post “merging a git repository”, we can move all those files to a subdirectory easily:

git filter-branch --prune-empty \
  --tree-filter 'mkdir -p new-subdir; \
  git ls-tree --name-only $GIT_COMMIT | \
  xargs -I FILES mv FILES new-subdir'

This means we can merge just a tiny part of a repository in very easily.

cd target-repo
git pull --allow-unrelated-histories filtered-repo

Modern versions of git want the --allow-unrelated-histories argument. You’ll need to rebase as well or those commits won’t have any of the stuff your existing repositories had which can prove pretty annoying.

Make sure it’s to your liking by checking out one of the revisions you just imported.

Splitting Subsets of a Git Repository

Merging Separate Git Repositories

On occasion I need to merge two git repositories together. Fortunately git has a solution which I usually have to google every time I do it.

Firstly you really need an empty commit on the root otherwise you get a strange commit in the repository where files are still in their original location. That can cause you some problems later since this commit will conflict with basically everything.

git checkout --orphan newroot
git rm -rf .

git commit --allow-empty -m "Root commit"
git rebase --onto newroot --root master
git branch -d newroot

Source: http://stackoverflow.com/questions/645450/insert-a-commit-before-the-root-commit-in-git

Moving the files themselves is also easy by using a tree-filter.

git filter-branch --prune-empty \
  --tree-filter 'mkdir -p new-subdir; \
  git ls-tree --name-only $GIT_COMMIT | \
  xargs -I FILES mv FILES new-subdir'

Note that this is a tree-filter which involves checking out each revision in order to work on it and is therefore quite slow for some repositories. You can probably optimise this into an index-filter which would not do that.

Since the repositories won’t conflict now (I assume that new-subdir does not exist in the repository you’re merging into) then a simple git pull will merge the filtered repository into the other repository.

The commit history will look a bit weird because the dates will be out of order but you will still have the full history.

Merging Separate Git Repositories