[[TOC]] Back to [ProvideFix How To Provide A Fix]. == Why git bundles == MERGE BRANCHES VIA PATCH MANAGER. Currently, the repo is folded into different public branches, letting a contributor choose on which of these branch his new patch is meant to be applied (see [RasdamanReleaseProcess#Branchingmodel here] for details). This wiki page is meant for developers who need to reflect a ''merge'' operations to the public repo: indeed a solution which provides both un-linearized history and submission to the [http://rasdaman.org/patchmanager patch manager] is to submit a ''bundle''. This allows no behind-the-scenes merge operations, and at the same time reflects the actual merge in the history of the repo, which otherwise won't be visible with patches: * REPO STATUS BEFORE MERGE : {{{ o-------A------B master \ C-------D feature_X }}} * REPO STATUS AFTER MERGING BUNDLE : {{{ o-------A------B------M master \ / C---------D feature_X }}} * REPO STATUS AFTER MERGING PATCH : {{{ o-------A------B------P master \ C---------D feature_X }}} Although git bundles are pretty powerful, that is they can add commits, merge branches, etc. It is important here to follow some rules when submitting a bundle, which mainly are: * 1 HEAD:[[BR]] Each patch must be associated to a ticket (see [StandardsAndGuideLines guidelines]), hence a git bundle should '''only perform the merge''' of two branches: no new "patches" should be stacked in, in none of the two branches (number of refs in the bundle will be checked anyway by the patch manager); * NAMING CONVENTIONS * the name of the merging '''commit''' must follow the naming convention "`Merge branch 'feature_X' into master`", so actually leave the default title that git sets; * the name of the '''bundle file''' must follow the pattern "`ticket:NNN_descriptionOfMerge.bundle`", referring to the ticket which justifies the merge. == Creating and submitting a bundle == When it's time to merge a branch which is publicly available, the situation can be very painful, but this is [http://weblog.masukomi.org/2008/07/12/handling-and-avoiding-conflicts-in-git another story]. First of all, the status of the two branches to be merged '''must''' be the _exactly_ the same before starting to merge. In this case, we can imagine we want to merge `feature_X` into `master`: {{{ o-------A-------B master \ D-------E feature_X }}} Going to the terminal, this means: {{{ #!sh $ git fetch origin # already up-to-date? otherwise pull new changes on both branches. $ git branch feature_X * master release_8.4 release_8.5 $ git merge feature_X --no-ff # ..and we assume there is no conflict, see # Check: $ git log --oneline -1 master 3f36d7f Merge branch 'feature_X' into master }}} After the merge, the situation (locally) is then: {{{ o-------A--------------M master \ / C----------D feature_X }}} To publish this on the public repo you can create the bundle, but first (again) remember that: * local snapshot of two branches must ''exactly'' be synchronized with that of the public repo; * consequently, the ''names'' of the merging branches must be the same as well (developers tend to open new branches for local development...). If all is fine, create the bundle: * Synopsis: {{{ #!sh $ git bundle create }}} * Example: {{{ #!sh # A graph view first: $ git log master --graph -4 * commit 3f36d7f1a19c3e4cfeab66807dd39f6d7fda771b |\ Merge: 5ee465b f7ed86b | | Author: Willie The Merger | | Date: Tue Oct 15 12:37:53 2013 +0200 | | | | Merge branch 'feature_X' into master | | | * commit f7ed86b6eba15e141202b44279d7f7afa4484944 | | Author: Jack Shortie | | Date: Tue Oct 8 12:34:54 2013 +0200 | | | | D | | | * commit 79e8805fe4b4ba2502be9c0e4b312b8b97e739b9 |/ Author: Johnnie Cannuccia | Date: Tue Oct 8 12:21:58 2013 +0200 | | C | * commit 5ee465b1ca5306590dce61e97acb97f1e88aa3c1 | Author: Piero Campalani | Date: Thu Aug 8 14:24:32 2013 +0200 | | A # Select the commits to be bundled # (e.g. use '^', which in our case is A (changeset:5ee465)) $ git log master ^5ee465 --oneline 3f36d7f Merge branch 'ProvaMerge' into ProvaMergeMaster f7ed86b D 79e8805 C # Create the bundle $ git bundle create ticket:XYZ_MergingFeature_xOnMaster.bundle master ^5ee465 Counting objects: 14, done. Delta compression using up to 2 threads. Compressing objects: 100% (9/9), done. Writing objects: 100% (9/9), 838 bytes, done. Total 9 (delta 8), reused 0 (delta 0) # See inside it: $ git list-heads ticket:XYZ_MergingFeature_xOnMaster.bundle 3f36d7f1a19c3e4cfeab66807dd39f6d7fda771b refs/heads/master }}} == Verifying the bundle == In case you need to locally verify that you produced a good bundle, you can create a new local repo and test it: {{{ #!sh # Create/init new empty repo $ echo `pwd` /home/rasdaman/rasdaman $ mkdir ~/test_repo $ cd ~/test_repo $ git init # Reset the history to where it was /before/ merging (A commit)(simulating public repo status) $ cd /home/rasdaman/rasdaman $ git remote add test_remote ~/test_repo $ git checkout master $ git reset --hard 5ee465 # Push two branches to the test repo $ git push test_remote master $ git push test_remote feature_X # Now move to the test repo and checkout on a branch you're not merging into: $ cd ~/test_repo $ git branch feature_X * master $ git checkout feature_x $ git branch * feature_X master # Apply the bundle: [verify &] apply $ git bundle verify /path/to/ticket:XYZ_MergingFeature_xOnMaster.bundle $ git fetch /path/to/ticket:XYZ_MergingFeature_xOnMaster.bundle master:master }}} == Fixing conflicts == During a merge, you can often stumble upon one, two or several thousands of conflicts: {{{ #!sh $ git merge feature_X --no-ff ... Automatic merge failed; fix conflicts and then commit the result. }}} In this case I would first suggest to configure `git` to present the conflicts with the so-called `diff3` style ([http://stackoverflow.com/questions/161813/how-do-i-fix-merge-conflicts-in-git thanks CoolAJ86]), which is: {{{ <<<<<<< Changes made on the branch that is being merged into. In most cases, this is the branch that I have currently checked out (i.e. HEAD). ||||||| The common ancestor version. ======= Changes made on the branch that is being merged in. This is often a feature/topic branch. >>>>>>> }}} It ''really'' helps you better understand the conflicts. You can configure it with: {{{ #!sh $ git merge --abort $ git config merge.conflictstyle diff3 }}} Then, [http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts as usual], fix conflicts, and commit: {{{ $ git merge feature_X --no-ff ... Auto-merging Makefile.am CONFLICT (content): Merge conflict in Makefile.am Automatic merge failed; fix conflicts and then commit the result. $ vim Makefile.am ...fix... $ git add Makefile.am $ git commit }}} ...and now you can proceed with the [wiki:GitCreateBundle#Creatingandsubmittingabundle bundle]. == I don't see any merge commit == ..you probably either forgot to add the `--no-ff` option when calling the merge (by default, but only if the merge is fast-forward, a normal single-parent commit is created), or somehow your .git/MERGE_HEAD passed away. This means you have your merge commit with lots of conflicts fixed that you want to re-apply. One idea is to: * save your merge to a patch, say `MERGE.patch` * reset to a pre-merge state and re-merge * if you have conflicts, just git-add everything to make git think you solved them, then commit * revert the (fake) commit and format a patch out of it, say `REVERT.patch` * reset again to a pre-merge state and again re-merge * re-git-add everything to mark conflicts solved (even though they aren't), but don't commit this time * apply `REVERT.patch` then `MERGE.patch` in the index * the two patches are applied, now you can git-commit. Let's say you applied a merge `M` of `feature_X` into `master`, but you see no merge commit in your history: {{{ o-------A--------------M master \ C----------D feature_X }}} {{{ #!sh # Patch your merge commit: $ git branch * master feature_X $ git format-patch HEAD~ MERGE.patch # Save the log for final checks $ git log -1 master > MERGE_FF.log # Re-merge $ git reset --hard A $ git merge --no-ff feature_X ... Automatic merge failed; fix conflicts and then commit the result. # Mark conflicts as solved, without applying changes $ git add folder1/ folder2/ ... $ git commit # let's call it M' # Revert your fake merge $ git revert -m 1 M' # let's call this commit rM' # Patch the reversion $ git format-patch HEAD~ REVERT.patch }}} Graphically, this is the current situation: {{{ o-------A--------------M'----------rM' master \ / C----------D feature_X }}} Now we roll-back to a pre-merge state again, then we merge, revert, and apply our initial patch: `(M'+rM'+M) = (M'-M'+M) = M` {{{ #!sh # Re-merge $ git reset --hard A $ git merge --no-ff feature_X ... Automatic merge failed; fix conflicts and then commit the result. # Mark conflicts as solved, without applying changes, but don't commit now $ git add folder1/ folder2/ ... # ... now we are @ M', without explicit commit # Apply rM' and M (without commiting) $ git apply --index REVERT.patch $ git apply --index MERGE.patch # Commit $ git commit [now you can customize the commit title] }}} Finally, we have our original merge, with true conflicts solution, but as a merge commit: {{{ o-------A--------------M master \ / C----------D feature_X }}} Verify the operation: {{{ #!sh $ git show M --stat > MERGE.log $ diff MERGE_FF.log MERGE.log 1,2c1 < commit < Merge: A D --- > commit 4c3 < Date: Wed Oct 23 17:24:04 2013 +0200 --- > Date: Wed Oct 23 15:55:02 2013 +0200 }}} If only the hash tags of the commits and the dates differ, then you applied exactly the same changes you made in your first merge. == Further reading == * [http://git-scm.com/2010/03/10/bundles.html Git's Little Bundle of Joy] * [http://stackoverflow.com/questions/3635952/how-to-use-git-bundle-for-keeping-development-in-sync How to use git-bundle for keeping development in sync] * [http://stackoverflow.com/questions/2285699/git-how-to-create-patches-for-a-merge Git: How to create patches for a merge?] * [http://git-scm.com/2010/03/02/undoing-merges.html Undoing Merges]