Rectangle 27 221

Merge trunk into a branch / tag

I couldn't properly follow the answers above, here's more of a dummies guide... I believe you can do this either way round to go trunk -> branch or branch -> trunk.

Checkout the branch / tag

  • Right-click on the root of the branch | Tortoise SVN | Merge ...
  • Merge Type: Merge a range of revisions | Click 'Next'
  • Merge revision range: Select the URL of the trunk directory that you copied to the branch / tag. Enter the revisions to merge or leave the field empty to merge all revisions | click 'Next'
  • Merge options: I just left these as default | click 'Merge'
  • This will merge the revisions into the checked out branch / tag
  • Then commit the merged changes to the branch / tag

I left out "Revision range to merge" and did a "Test Merge". It was what I needed: the range was automatically set for me (from when the branch was done to the last revision in the branch)

@Lian I did the same thing to merge from trunk into branch; leave the revision range blank if you want the latest version of the files from trunk to be merged with the branch files.

The current version of Tortoise SVN now has an option to merge all revisions instead of leaving the Revision range blank in step 4.

svn - Using TortoiseSVN how do I merge changes from the trunk to a bra...

svn tortoisesvn merge branch
Rectangle 27 13

Digging some more into the matter, I found out that git supports setting svn:mergeinfo property on the SVN branch when dcommit'ing:

git svn dcommit --mergeinfo "/branches/somebranch:1-3"

NB! the svn:mergeinfo is overwritten with whatever is given on the command-line, so be careful to list previous merges too.

config key: svn.pushmergeinfo

I had some troubles with the automatic mergeinfo - for one reason or the other GIT calculated it wrong and I couldn't get it to work.

To automate the process, I wrote a shell script git-merge-svn which can be used to merge two SVN branches with correct svn:mergeinfo set on the dcommit.

  • the branch is not merged in git - will do git merge beforehand
  • the branches have been already merged in git (but not in SVN) - will traverse until previous ancestor for the merged commit revisions.

With this script I was able to produce these merges solely on git-side and retain the merge info so that GIT graph shows the log nicely:

dcommit
  • check out testtunk6 - yes, I know I made a typo in the name ;-)
git merge-svn devel6
% git merge-svn devel6
About to do an SVN merge: devel6 -> testtunk6

* NEW MERGE COMMIT
|\
| * devel6 [7b71187] (r102)
* | testtunk6 [0682a45] (r101)
 \|
  * [273d6d6] (r100)


STEP 1: GIT merge
Executing:
  git merge devel6

Continue? (y/n) [n]: y
Merge made by the 'recursive' strategy.
 testfile | 1 +
 1 file changed, 1 insertion(+)

STEP 2: SVN dcommit

executing:
git svn dcommit --mergeinfo
/idp/branches/devel:9-32,35-41 /idp/branches/devel6:89 /idp/branches/devel6:94 /idp/branches/devel6:93 /idp/branches/devel6:96 /idp/branches/devel6:97 /idp/branches/devel6:99 /idp/branches/devel6:100 /idp/branches/devel6:102

Continue? (y/n) [n]: y
Committing to https://my.svn.host/svn/auth/idp/branches/testtunk6 ...
  M testfile
Committed r103
  M testfile
Found merge parent (svn:mergeinfo prop): 7b71187fc371d3f86658c5850009e63be88157ac
r103 = 87759323cbadd38bac78087d57b6870a926287e7 (refs/remotes/svn/testtunk6)
No changes between 3fb2168cfbbe605fbd810d76513443203a85a549 and refs/remotes/svn/testtunk6
Resetting to the latest refs/remotes/svn/testtunk6

Is there any way to get this to work: git-merge-svn master mybranch followed immediately by git-merge-svn mybranch master? The 2nd merge attempts to dcommit to mybranch, and if you try again, it says it is already merged (a lie probably due to git master being merged with a sha hash that corresponds to the sha of mybranch despite not being committed to svn -- though the git-svn-id line is there as it was git merged to a commit that was dcommitted from mybranch to svn).

@ShadowCreeper - actually, the message is probably true - SVN reports that the commits are already present in mybranch, which they are. Your expected result would be that mybranch and master point to same SHA1, but this is impossible with SVN - it's branches are essentially folders and two branches must point to different folders. So, in SVN all is at it's best, while in Git you can't make use of full functionality - this is how it is.

In short - any Git branch that you "push" to SVN will stay as separate branch and can not be "fast-forwarded" into another branch in Git sense, only merged in regular SVN-sense.

--rebase
--no-ff
git-merge-svn

git svn - Git-svn merge two SVN branches - Stack Overflow

git git-svn
Rectangle 27 4

Git and Svn have different data structure to keep a history.

Svn uses a simple tree. I.e. each commit has only one parent, but one commit could have several childs (branches). So, Svn doesn't support merges. The thing they call as "merge" is actually changeset porting, the closest analogy in git is rebase or maybe cherry-pick. From version 1.5 Svn supports a metainfo property svn:mergeinfo which helps somehow to track what was "merged", however it looks mostly as a workaround, that explains why branches in Svn are so hard to use. Merge point is a commit which squashes all merged changesets and conflict resolution into one changeset, probably annotated with the svn:mergeinfo property.

Git uses Directed acyclic graph which is very natural way to describe history merging and branching. A merge point is just another commit with two (or more!) parents. So, your (3) on the picture is a merge commit. So, all history looks natural, it has all commits reachable on a history graph from the current point.

Git-Svn bridge tries do the best to handle Svn design drawback, before doing dcommit it usually rebases all merged commits on the top of the current Svn branch. Asof ~2 years ago, git-svn was not able to supply svn:mergeinfo, so the thing you are asking is impossible. Moreover, when you are dcommiting, git creates a "twin" commit "hardly" linked to a svn commit, so it rewrites original commit.

Thanks for the explanation. I ended up with workflow that I rebase -i all one-off branches to devel and at the release point, I just create a patch and apply that as a single commit to the master. This way master only consists of release-commits and dev-history is in the devel branch only. Good enough solution.

@Laas Do you mean you squash all commits into one using rebase -i? Yeah... could work, and quite easy to do, however it screws history, but looks like it is the best you could achieve using svn.

@Laas Or alternative solution would be cherry-picking range of commits with -x flag, at least it will keep commits separately implicitly linking them by the "cherry picked from commit" comment. This comment is processed by git log and some other commands, which would simplify some stuff.

git svn - Git-svn merge two SVN branches - Stack Overflow

git git-svn
Rectangle 27 22

The git-svn man page recommends that you don't use merge. This is one side effect. Since you are rebasing the branch (git svn rebase is a bit like "git pull --rebase") it effectively rewrites history. It may throw away any local commits that are already upstream in subversion, such as the merge, and keep only those commits that really exist in the svn repository. Since a trivial merge commit of a local branch has no equivalent in SVN, you only commit the "real" changes, so these are the only changes seen in your new rebased master branch.

Ideally your local branch should merge fast-forward only, i.e. no merge commit is generated. If this is not the case, then you should consider rebasing your local branch onto master instead of merging it. That avoids creating a merge commit completely.

+1 for git rebase master

git svn - Why does git svn dcommit lose the history of merge commits f...

git git-svn rebase
Rectangle 27 155

  • Switch the working copy to the trunk (SVN Switch)
  • Merge the branch into the working copy (SVN Merge)
  • Make sure everything still compiles and works
  • Commit the working copy (the trunk)

In a team environment I would suggest that you first merge the latest modifications from the trunk in your branch, make sure that everything compiles and works, then do the above steps (which will be trivial since you've already tested the changes).

In step 5, I mention killing the branch. That's because once a branch from a feature is in the trunk, it should be considered as part of the trunk. In that case the branch should be killed so that no one keeps working on it. If major modifications are needed for that feature, you should create a new branch for that.

The only branches that I don't kill are maintenance and release branches, unless a particular release is no longer supported.

No matter what, you always have access to every revision so killing a branch is only used to prevent other developers from developing on a dead branch.

This is the best answer so far, but it could be a little more precise: 1. Switch working copy to trunk (SVN Switch), 2. Merge the branch into the working copy (SVN Merge), 3. Compile the working copy, 4. Commit the working copy (SVN Commit). ...

Thanks, I did this and it worked as I wanted. I was also able to tag the code with these same steps. In step 5, what are the reasons for killing the branch? Is it to save space?

Is the first step (switch the working copy to trunk) only necessary if don't have a seperate branch and trunk working copy?

I think a major piece of detail that's missing here is what folder you click on for each step, so you know the context of each step.

Use TortoiseSVN to merge branch changes with the trunk - Stack Overflo...

tortoisesvn merge branch trunk
Rectangle 27 168

Actually, I found an even better way with the --no-ff option on git merge. All this squash technic I used before is no longer required.

My new workflow is now as follows:

I have a "master" branch that is the only branch that I dcommit from and that clone the SVN repository (-s assume you have a standard SVN layout in the repository trunk/, branches/, and tags/):

git svn clone [-s] <svn-url>

I work on a local branch "work" (-b creates the branch "work")

git checkout -b work

commit locally into the "work" branch (-s to sign-off your commit message). In the sequel, I assume you made 3 local commits

...
(work)$> git commit -s -m "msg 1"
...
(work)$> git commit -s -m "msg 2"
...
(work)$> git commit -s -m "msg 3"

[Eventually] stash the modifications you don't want to see committed on the SVN server (often you commented some code in the main file just because you want to accelerate the compilation and focus on a given feature)

(work)$> git stash

rebase the master branch with the SVN repository (to update from the SVN server)

(work)$> git checkout master
(master)$> git svn rebase

go back to the work branch and rebase with master

(master)$> git checkout work
(work)$> git rebase master
(work)$> git log --graph --oneline --decorate

Now it's time to merge all three commits from the "work" branch into "master" using this wonderful --no-ff option

(work)$> git checkout master
(master)$> git merge --no-ff work
  • You can notice the status of the logs: (master)$> git log --graph --oneline --decorate * 56a779b (work, master) Merge branch 'work' |\ | * af6f7ae msg 3 | * 8750643 msg 2 | * 08464ae msg 1 |/ * 21e20fa (git-svn) last svn commit

Now you probably want to edit (amend) the last commit for your SVN dudes (otherwise they will only see a single commit with the message "Merge branch 'work'"

(master)$> git commit --amend

Finally commit on the SVN server

(master)$> git svn dcommit

Go back to work and eventually recover your stashed files:

(master)$> git checkout work
(work)$> git stash pop

This is EXACTLY the work flow this git n00b was looking for. Create a local branch to fix a bug, do whatever, then send it up to svn with a SINGLE commit. Using the highest rated answer here messed up what I was doing - couldn't git svn rebase without errors.

Isn't this exactly what the git-svn docs quoted in the op warn against? By running merge with the --no-ff option, you are explicitly creating a merge commit (a commit with two parents) instead of a fast-forward. To ensure all commits in the svn-tracking branch are single-parent commits, all merges must either be fast-forwards (--ff-only can help with this) or, if trunk has changed behind your back, a --squash, right?

This works for a one-off branch that you immediately delete, but git svn dcommit rewrites the git commit that you give it. This means that you lose its other parent, and now your git repo has no record that you ever merged that branch into master. This can also leave your working directory in an inconsistent state.

git merge --no-ff work -m "commit message"
git commit --amend

for me I'd prefer to use "git merge --ff-only work" since I want to preserve all my commits and not just the last one

Is git-svn dcommit after merging in git dangerous? - Stack Overflow

svn git merge branch git-svn
Rectangle 27 8

Greg Hewgill answer on top is not safe! If any new commits appeared on trunk between the two "git svn rebase", the merge will not be fast forward.

It can be ensured by using "--ff-only" flag to the git-merge, but I usually do not run "git svn rebase" in the branch, only "git rebase master" on it (assuming it is only a local branch). Then afterwards a "git merge thebranch" is guaranteed to be fast forward.

Is git-svn dcommit after merging in git dangerous? - Stack Overflow

svn git merge branch git-svn
Rectangle 27 26

The behavior depends on which version your repository has. Subversion 1.5 allows 4 types of merge:

Subversion before 1.5 only allowed the first 2 formats.

Technically you can perform all merges with the first two methods, but the last two enable subversion 1.5's merge tracking.

TortoiseSVN's options merge a range or revisions maps to method 3 when your repository is 1.5+ or to method one when your repository is older.

When merging features over to a release/maintenance branch you should use the 'Merge a range of revisions' command.

Only when you want to merge all features of a branch back to a parent branch (commonly trunk) you should look into using 'Reintegrate a branch'.

And the last command -Merge two different trees- is only usefull when you want to step outside the normal branching behavior. (E.g. Comparing different releases and then merging the differenct to yet another branch)

svn - Using TortoiseSVN how do I merge changes from the trunk to a bra...

svn tortoisesvn merge branch
Rectangle 27 49

Creating local branches is definitely possible with git-svn. As long as you're just using local branches for yourself, and not trying to use git to merge between upstream svn branches, you should be fine.

I have a "master" branch that I use to track the svn server. This is the only branch that I dcommit from. If I'm doing some work, I create a topic branch and work away on it. When I want to commit it, I do the following:

I also have another situation where I need to maintain some local changes (for debugging) that should never be pushed up to svn. For that, I have the above master branch but also a branch called "work" where I normally do work. Topic branches are branched off work. When I want to commit work there, I checkout master and use cherry-pick to pick the commits from the work branch that I want to commit to svn. This is because I want to avoid committing the three local change commits. Then, I dcommit from the master branch and rebase everything.

It is worthwhile running git svn dcommit -n first to make sure that you are about to commit exactly what you intend to commit. Unlike git, rewriting history in svn is hard!

I feel that there must be a better way to merge the change on a topic branch while skipping those local change commits than using cherry-pick, so if anybody has any ideas they would be welcome.

If I understand this correctly, in git, merging git with svn is OK, but not svn with svn? So I can't merge my svn/branch with svn/trunk in git?

Rewriting history in SVN is hard if you want to do something trivial. In non-trivial cases its practically impossible.

Greg Hewgill's answer has a lot of votes, but I believe it's wrong. Merging from topic_branch into master is only safe if it's just a fast-forward merge. If it's a real merge requiring a merge commit, then the merge commit will be lost when you dcommit. The next time you try to merge topic_branch into master, git thinks the first merge never happened, and all hell breaks loose. See the question Why does git svn dcommit lose the history of merge commits for local branches?

@Greg Hewgill, the edit isn't clear. You wrote that the rebase "makes the next commit a fast-forward merge." I don't know what that means, because a fast-forward merge doesn't involve a commit, but perhaps you meant "makes the next merge a fast-forward merge". But if that's what you meant, it's not correct. Whether a merge from topic_branch into master is a fast-forward merge or not depends on whether any commits have been made on master since the branch point. When you rebase master, that creates new commits on master, so a subsequent merge is necessarily not a fast-forward merge.

@Aaron: Yeah I don't know what I was thinking there. I've fixed it again, hopefully that makes sense. One of the troubles is that there's so many ways to do things in Git, that it takes quite some explanation to describe a specific sequence of actions.

Is git-svn dcommit after merging in git dangerous? - Stack Overflow

svn git merge branch git-svn
Rectangle 27 11

Actually I fixed it using the "merge two different branches" option to merge the trunk and the branch into my working copy. Then I committed that to the trunk.

This answer doesn't really explain what you did. No examples, not even a link to the requisite section of the manual.

In hindsight, no it doesn't. However, as this was my own answer on the same day as the question, it was the best answer for a few months. I'd like to presume it makes sense if you still use Tortoise SVN 1.6 though. I have accepted Gray's answer as the accepted answer now instead.

Example: svn merge ^/tags/w.x ^/tags/y.z . The reintegrate error popped up for me when using 1.8 and merging into the trunk where the merge source had had a specific revision previously merged into it from the trunk. 1.8 appeared to decide that a reintegrate merge was being attempted, which it wasn't. A dry-run merge with 1.6 would work fine, but the two URL merge fits too.

The precise scenario that failed with 1.8 was copying a tag from some revisions back for a patch release, cherry picking a change from the trunk to backport by a merge into the patched tag, making a further change to the patched tag, and merging that back into the trunk. The changes between the base tag and the patched version are what need to be merged back to the trunk, and a 2 URL merge works a treat for that.

I should have read this answer before spending 3 days trying to understand what was going on. I still don't understand why I have had this problem but suspect the comment from @Nick is the reason - and now things are working I'm not going to look any further...

svn - Reintegrate can only be used if revisions X through Y were previ...

svn tortoisesvn
Rectangle 27 3

I investigated the same problem. It is "feature" in Tortoise SVN 1.6.5. TortoiseSVN 1.5 works fine with our repositoty (SVN 1.5). TortoiseSVN 1.6.5 when rebasing adds files from mainline as NEW (without saving merge-history). And reintegrating branch resuls in treating those files as conflicting with mainline.

I solved the problem by using feature of TortoiseSVN 1.6 "reintegrate branch". It's specifically purposed for feature-branches.

Thanks. Out of all the discussion on SO about this "tree conflict" issue, this one helped me fix it properly.

SVN - unable to merge branch back into trunk - numerous tree-conflicts...

svn merge tree-conflict
Rectangle 27 1

Well, you are victim of "Refactoring Hell" in SVN - it's still a Big Problem

/trunk
/branches/x
file1.xml
  • In WC of branch, select "Merge" for individual file, not parent folder, and trunk's file1.xml as merge source.
  • Repeat these merges for all (moved) files with tree-conflict
  • Enable (bundled with THG 3.0) hgsubversion extension
  • (because mergesets can't be pushed back to Subversion) archive tip of Mercurial repo into unversioned files, which must replace WC of you Subversion repository and commit this state of changes (you'll get broken history at this revision in Subversion)
  • Return to work with Subversion repository and refactored code

This makes sense to me. I appreciate you taking the time to help me out. I tried this out and it worked. Luckily only small parts of the code are being refactored and I'm the only developer working it. So merging is less horrible than it could be!

Tortoise SVN - Merge Trunk into Branch - Tree Conflict - Stack Overflo...

svn merge tortoisesvn tree-conflict
Rectangle 27 71

Sounds like you're using the pre-1.5 merge style and trying to reintegrate the branch into trunk. In that case, what you want to do is first ensure all the trunk changes have been merged in to the branch, and then instead of range-merging the branch to a working copy that points to the trunk, you want to merge "FROM trunk@HEAD TO branch@HEAD" with the working copy pointing to trunk. In essence:

This works if you've already merged all the trunk changes to the branch, because then the only difference between trunk and branch are the changes made in the branch.

1.5 and onwards you can skip the revision range in the first merge and use something like "svn merge --reintegrate branch" for the second merge (can't recall the TSVN gui specifics). On the downside, after reintegrating you'll have to re-branch because the reintegrate does something funny to the mergeinfo.

Thanks @Rytmis, I just managed to pull this off, but I want to offer a translation for Tortoise users. 1) Switch your working copy to the branch (if it isn't already) 2) Right-click working copy, TortoiseSVN > Merge > "Merge a range of revisions", click Next 3) URL to merge from = Trunk, click Next, Merge 4) Switch working copy to Trunk 5) Right-click working copy, TortoiseSVN > Merge > "Merge two different trees", click Next 6) From: Trunk (use HEAD revision) To: Branch (use HEAD revision) 7) Click Next, Merge. 8) Commit your working copy. DONE

This explanation has resolved several conflicts in our process. Thanks guys :)

These instructions are not really applicable for versions of SVN >= 1.5, and I have long since given up on using SVN for anything other than simple checkouts from other peoples' systems, so I'm afraid I can't help you here. :(

SVN - unable to merge branch back into trunk - numerous tree-conflicts...

svn merge tree-conflict
Rectangle 27 56

If your working directory points to the trunk, then you should be able to merge your branch with:

svn merge https://HOST/repository/branches/branch_1

be sure to be to issue this command in the root directory of your trunk

why do people explain things in such roundabout an unnecessarily complex ways? This is so simple. This should be the first thing people think of. This is the minimal fundamental information required.

svn - Merge a Branch into Trunk - Stack Overflow

svn version-control merge
Rectangle 27 33

Short answer: You can use git however you like (see below for a simple workflow), including merge. Just make sure follow each 'git merge work' with 'git branch -d work' to delete the temporary work branch.

Background explanation: The merge/dcommit problem is that whenever you 'git svn dcommit' a branch, the merge history of that branch is 'flattened': git forgets about all merge operations that went into this branch: Just the file contents is preserved, but the fact that this content (partially) came from a specific other branch is lost. See: Why does git svn dcommit lose the history of merge commits for local branches?

(Note: There is not much that git-svn could do about it: svn simply doesn't understand the much more powerful git merges. So, inside the svn repository this merge information cannot be represented in any way.)

But this is the whole problem. If you delete the 'work' branch after it has been merged into the 'master branch' then your git repository is 100% clean and looks exactly like your svn repository.

My workflow: Of course, I first cloned the remote svn repository into a local git repository (this may take some time):

$> git svn clone <svn-repository-url> <local-directory>

All work then happens inside the "local-directory". Whenever I need to get updates from the server (like 'svn update'), I do:

I do all my development work in a separate branch 'work' that is created like this:

$> git checkout -b work

Of course, you can create as many branches for your work as you like and merge and rebase between them as you like (just delete them when you are done with them --- as discussed below). In my normal work, I commit very frequently:

$> git commit -am '-- finished a little piece of work'

The next step (git rebase -i) is optional --- it's just cleaning up the history before archiving it on svn: Once I reached a stable mile stone that I want to share with others, I rewrite the history of this 'work' branch and clean up the commit messages (other developers don't need to see all the little steps and mistakes that I made on the way --- just the result). For this, I do

$> git log

and copy the sha-1 hash of the last commit that is live in the svn repository (as indicated by a git-svn-id). Then I call

$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb

Just paste sha-1 hash of our last svn commit instead of mine. You may want to read the documentation with 'git help rebase' for the details. In short: this command first opens an editor presenting your commits ---- just change 'pick' to 'squash' for all those commits that you want to squash with previous commits. Of course, the first line should stay as a 'pick'. In this way, you can condense your many little commits into one or more meaningful units. Save and exit the editor. You will get another editor asking you to rewrite the commit log messages.

In short: After I finish 'code hacking', I massage my 'work' branch until it looks how I want to present it to the other programmers (or how I want to see the work in a few weeks time when I browse history).

In order to push the changes to the svn repository, I do:

Now we are back at the old 'master' branch updated with all changes that happened in the mean time in the svn repository (your new changes are hidden in the 'work' branch).

If there are changes that may clash with your new 'work' changes, you have to resolve them locally before you may push your new work (see details further below). Then, we can push our changes to svn:

$> git checkout master
$> git merge work        # (1) merge your 'work' into 'master'
$> git branch -d work    # (2) remove the work branch immediately after merging
$> git svn dcommit       # (3) push your changes to the svn repository

Note 1: The command 'git branch -d work' is quite safe: It only allows you to delete branches that you don't need anymore (because they are already merged into your current branch). If you execute this command by mistake before merging your work with the 'master' branch, you get an error message.

Note 2: Make sure to delete your branch with 'git branch -d work' between merging and dcommit: If you try to delete the branch after dcommit, you get an error message: When you do 'git svn dcommit', git forgets that your branch has been merged with 'master'. You have to remove it with 'git branch -D work' which doesn't do the safety check.

Now, I immediately create a new 'work' branch to avoid accidentally hacking on the 'master' branch:

$> git checkout -b work
$> git branch            # show my branches:
  master
* work

Integrating your 'work' with changes on svn: Here is what I do when 'git svn rebase' reveals that others changed the svn repository while I was working on my 'work' branch:

$> git checkout master
$> git svn rebase              # 'svn pull' changes
$> git checkout work           # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master            # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed

$> git checkout master         # try again to push my changes
$> git svn rebase              # hopefully no further changes to merge
$> git merge integration       # (1) merge your work with theirs
$> git branch -d work          # (2) remove branches that are merged
$> git branch -d integration   # (2) remove branches that are merged
$> git svn dcommit             # (3) push your changes to the svn repository

More powerful solutions exist: The presented workflow is simplistic: It uses the powers of git only within each round of 'update/hack/dcommit' --- but leaves the long-term project history just as linear as the svn repository. This is ok if you just want to start using git merges in small first steps in a legacy svn project.

When you become more familiar with git merging, feel free to explore other workflows: If you know what you are doing, you can mix git merges with svn merges (Using git-svn (or similar) just to help out with svn merge?)

This seems unnecessarily complex. I've heard of people doing git merge --squash work, why not do this? I can see doing squash commits in the branch before merging if you are creating more than one 'pick' (say you have 8 commits and you are turning each of 4 commits into 1, and merging 2 commits to master). Also when updating my 'work' branch, I do rebase, it's simpler than creating another branch for my branch and doing merges...

Is git-svn dcommit after merging in git dangerous? - Stack Overflow

svn git merge branch git-svn
Rectangle 27 3

Something that worked for me in tortoise SVN: instead of merging all revisions from branch, choose specific range and manually select all your revisions from the branch.

Thank you for such a basic idea. Of all the answers, this was not only the least complicated, but it was the only one that worked for me.

svn - Reintegrate can only be used if revisions X through Y were previ...

svn tortoisesvn
Rectangle 27 11

You should use "merge a range of revision".

To merge changes from the trunk to a branch, inside the branch working copy choose "merge range of revisions" and enter the trunk URL and the start and end revisions to merge.

The same in the opposite way to merge a branch in the trunk.

svn - Using TortoiseSVN how do I merge changes from the trunk to a bra...

svn tortoisesvn merge branch
Rectangle 27 15

Last revision merged from trunk to branch can be found by running this command inside the working copy directory:

svn log -v --stop-on-copy

That just stops the log when the branch was created; it doesn't show any merges that happened after that point.

Because, with that little caveat from @moswald, this can be quite useful to know. I don't see the problem. I don't usually have long lived branches (at most one week), so I normally only pull from trunk right before reintegration.

svn - Merge trunk to branch in Subversion - Stack Overflow

svn merge
Rectangle 27 3

svn merge -r11:8 path/

version control - Jump back in time in SVN - Stack Overflow

svn version-control tortoisesvn branch
Rectangle 27 537

And oh, by the way, Subversion still sucks

The claim of why merging is better in a DVCS than in Subversion was largely based on how branching and merge worked in Subversion a while ago. Subversion prior to 1.5.0 didn't store any information about when branches were merged, thus when you wanted to merge you had to specify which range of revisions that had to be merged.

1   2   4     6     8
trunk o-->o-->o---->o---->o
       \
        \   3     5     7
b1       +->o---->o---->o

When we want to merge b1's changes into the trunk we'd issue the following command, while standing on a folder that has trunk checked out:

svn merge -r 2:7 {link to branch b1}

which will attempt to merge the changes from b1 into your local working directory. And then you commit the changes after you resolve any conflicts and tested the result. When you commit the revision tree would look like this:

1   2   4     6     8   9
trunk o-->o-->o---->o---->o-->o      "the merge commit is at r9"
       \
        \   3     5     7
b1       +->o---->o---->o

However this way of specifying ranges of revisions gets quickly out of hand when the version tree grows as subversion didn't have any meta data on when and what revisions got merged together. Ponder on what happens later:

12        14
trunk  -->o-------->o
                                     "Okay, so when did we merge last time?"
              13        15
b1     ----->o-------->o

This is largely an issue by the repository design that Subversion has, in order to create a branch you need to create a new virtual directory in the repository which will house a copy of the trunk but it doesn't store any information regarding when and what things got merged back in. That will lead to nasty merge conflicts at times. What was even worse is that Subversion used two-way merging by default, which has some crippling limitations in automatic merging when two branch heads are not compared with their common ancestor.

To mitigate this Subversion now stores meta data for branch and merge. That would solve all problems right?

On a centralized system, like subversion, virtual directories suck. Why? Because everyone has access to view them even the garbage experimental ones. Branching is good if you want to experiment but you don't want to see everyones' and their aunts experimentation. This is serious cognitive noise. The more branches you add, the more crap you'll get to see.

The more public branches you have in a repository the harder it will be to keep track of all the different branches. So the question you'll have is if the branch is still in development or if it is really dead which is hard to tell in any centralized version control system.

Most of the time, from what I've seen, an organization will default to use one big branch anyway. Which is a shame because that in turn will be difficult to keep track of testing and release versions, and whatever else good comes from branching.

There is a very simple reason why: branching is a first-class concept. There are no virtual directories by design and branches are hard objects in DVCS which it needs to be such in order to work simply with synchronization of repositories (i.e. push and pull).

The first thing you do when you work with a DVCS is to clone repositories (git's clone, hg's clone and bzr's branch). Cloning is conceptually the same thing as creating a branch in version control. Some call this forking or branching (although the latter is often also used to refer to co-located branches), but it's just the same thing. Every user runs their own repository which means you have a per-user branching going on.

The version structure is not a tree, but rather a graph instead. More specifically a directed acyclic graph (DAG, meaning a graph that doesn't have any cycles). You really don't need to dwell into the specifics of a DAG other than each commit has one or more parent references (which what the commit was based on). So the following graphs will show the arrows between revisions in reverse because of this.

A very simple example of merging would be this; imagine a central repository called origin and a user, Alice, cloning the repository to her machine.

a   b   c
origin   o<---o<---o
                   ^master
         |
         | clone
         v

         a   b   c
alice    o<---o<---o
                   ^master
                   ^origin/master

What happens during a clone is that every revision is copied to Alice exactly as they were (which is validated by the uniquely identifiable hash-id's), and marks where the origin's branches are at.

Alice then works on her repo, committing in her own repository and decides to push her changes:

a   b   c
origin   o<---o<---o
                   ^ master

              "what'll happen after a push?"


         a   b   c   d   e
alice    o<---o<---o<---o<---o
                             ^master
                   ^origin/master

The solution is rather simple, the only thing that the origin repository needs to do is to take in all the new revisions and move it's branch to the newest revision (which git calls "fast-forward"):

a   b   c   d   e
origin   o<---o<---o<---o<---o
                             ^ master

         a   b   c   d   e
alice    o<---o<---o<---o<---o
                             ^master
                             ^origin/master

The use case, which I illustrated above, doesn't even need to merge anything. So the issue really isn't with merging algorithms since three-way merge algorithm is pretty much the same between all version control systems. The issue is more about structure than anything.

Admittedly the above example is a very simple use case, so lets do a much more twisted one albeit a more common one. Remember that origin started out with three revisions? Well, the guy who did them, lets call him Bob, has been working on his own and made a commit on his own repository:

a   b   c   f
bob      o<---o<---o<---o
                        ^ master
                   ^ origin/master

                   "can Bob push his changes?" 

         a   b   c   d   e
origin   o<---o<---o<---o<---o
                             ^ master

Now Bob can't push his changes directly to the origin repository. How the system detects this is by checking if Bob's revisions directly descents from origin's, which in this case doesn't. Any attempt to push will result into the system saying something akin to "Uh... I'm afraid can't let you do that Bob."

So Bob has to pull-in and then merge the changes (with git's pull; or hg's pull and merge; or bzr's merge). This is a two-step process. First Bob has to fetch the new revisions, which will copy them as they are from the origin repository. We can now see that the graph diverges:

v master
         a   b   c   f
bob      o<---o<---o<---o
                   ^
                   |    d   e
                   +----o<---o
                             ^ origin/master

         a   b   c   d   e
origin   o<---o<---o<---o<---o
                             ^ master

The second step of the pull process is to merge the diverging tips and make a commit of the result:

Hopefully the merge won't run into conflicts (if you anticipate them you can do the two steps manually in git with fetch and merge). What later needs to be done is to push in those changes again to origin, which will result into a fast-forward merge since the merge commit is a direct descendant of the latest in the origin repository:

v origin/master
                                 v master
         a   b   c   f       1
bob      o<---o<---o<---o<-------o
                   ^             |
                   |    d   e  |
                   +----o<---o<--+

                                 v master
         a   b   c   f       1
origin   o<---o<---o<---o<-------o
                   ^             |
                   |    d   e  |
                   +----o<---o<--+

There is another option to merge in git and hg, called rebase, which'll move Bob's changes to after the newest changes. Since I don't want this answer to be any more verbose I'll let you read the git, mercurial or bazaar docs about that instead.

As an exercise for the reader, try drawing out how it'll work out with another user involved. It is similarly done as the example above with Bob. Merging between repositories is easier than what you'd think because all the revisions/commits are uniquely identifiable.

There is also the issue of sending patches between each developer, that was a huge problem in Subversion which is mitigated in git, hg and bzr by uniquely identifiable revisions. Once someone has merged his changes (i.e. made a merge commit) and sends it for everyone else in the team to consume by either pushing to a central repository or sending patches then they don't have to worry about the merge, because it already happened. Martin Fowler calls this way of working promiscuous integration.

Because the structure is different from Subversion, by instead employing a DAG, it enables branching and merging to be done in an easier manner not only for the system but for the user as well.

I don't agree with your branches==noise argument. Lots of branches doesn't confuse people because the lead dev should tell people which branch to use for big features... so two devs might work on branch X to add "flying dinosaurs", 3 might work on Y to "let you throw cars at people"

John: Yes, for small number of branches there is little noise and is managable. But come back after you've witnessed 50+ branches and tags or so in subversion or clear case where most of them you can't tell if they're active or not. Usability issue from the tools aside; why have all that litter around in your repository? At least in p4 (since a user's "workspace" is essentially a per-user branch), git or hg you've got the option to not let everyone know about the changes you do until you push them upstream, which is a safe-guard for when the changes are relevant to others.

I don't get your "too many experimental branches are noise argument either, @Spoike. We have a "Users" folder where every user has his own folder. There he can branch as often as he wishes. Branches are inexpensive in Subversion and if you ignore the folders of the other users (why should you care about them anyway), then you don't see noise. But for me merging in SVN does not suck (and I do it often, and no, it's not a small project). So maybe I do something wrong ;) Nevertheless the merging of Git and Mercurial is superior and you pointed it out nicely.

In svn it's easy to kill inactive branches, you just delete them. The fact that people don't remove unused branches therefore creating clutter is just a matter of housekeeping. You could just as easily wind up with lots of temporary branches in Git as well. In my workplace we use a "temp-branches" top-level directory in addition to the standard ones - personal branches and experimental branches go in there instead of cluttering the branches directory where "official" lines of code are kept (we don't use feature branches).

Does this mean then, that from v1.5 subversion can at least merge as well as git can?

How and/or why is merging in Git better than in SVN? - Stack Overflow

svn git version-control mercurial merge