TFS merging issue from branch to Trunk - visual-studio

We have a Trunk. From this trunk we had taken a branch (V01.01 SP). From this branch (V01.01 SP) we had taken another branch (V01.01.01 REL).
We are implementing the new changes in the branch (V01.01 SP).
After completing the implementation in branch (V01.01 SP) the changes have been merged successfully to the branch (V01.01.01 REL).
After that we have done lot of changes in the branch (V01.01 SP).
Now we want to merge the branch (V01.01.01 REL) to Trunk.
The source is (V01.01.01 REL) and the target is Trunk.
While merging we have found one issue,
some of the changes from the source are not merged to Target.
Instead of that, it takes the content from the target.
It shows the changes in source and target file in a rectangular box. But it automatically ticks the target rectangular box.
How can I changes this to take from source file.

In TFS, you could only merge to directly related branches(parent or child). There is no merge relationship between branch (V01.01.01 REL) and Trunk in your case (grandparent or grandchild).
You need to pefer a baseless merge, use tf merge command.
tf merge /baseless <<source path>> <<target path>> /recursive
/baseless
Performs a merge without a base version. That is, allows the user to
merge files and folders that do not have a merge relationship. After a
baseless merge, a merge relationship exists, and future merges do not
have to be baseless.
Note Baseless merges cannot delete files in the target. You can manually carry over such changes.

Related

What is the optimal way to only sync certain file extensions and exclude other file extensions between separate git branches?

Given 3 branches say master, b1, and b2.
The master branch only cares about *.txt files. It needs to ignore everything else.
Branch b1 only needs what is included by master and say *.h, *.c, *.cpp files, and ignore everything else.
Branch b2 also only needs to include the ones included by master and say *.jpg, *.png, *.html, *.css etc. ignoring everything else.
In short, master branch contains information only common to all branches. Example use case: Branch b1 is used to generate output files to be consumed by branch b2, but both contain some information shared with master.
So, what is the optimal way to sync only those common files between master, b1, and b2, and have each branch to only include certain file extensions in its branch and ignore everything else it doesn't need?
I also looked at alternatives of having separate git repos or submodules or subtrees, but the directory structures or nesting patterns created little difficulties. Is there a better way to solve this problem?
Let me start with this because it's perhaps more useful:
Is there a better way to solve this problem?
You could, in theory, not bother with a master branch at all. Have three branches, none of which holds final-assembled-results. Do the assembly outside of Git. If desired, make an "orphan branch" (or use a tag) to record the assembled result, or just keep the assembled results in a completely different repository. But these all result in those sorts of little difficulties you mention.
What goes wrong
Git simply doesn't work the way you want: you cannot (usefully anyway) "care about" some files and have other "uncared-about" files with the "caring" switching around based on the branch. That's because "branches", in the sense you're using the word, do not exist.
Now, that's a strong statement and it needs justification. Clearly, branches do exist. The problem lies in the meaning of the word branch. It has too many meanings and people just sort of flip between them, without realizing that they're doing this, and that gets them into trouble. (See also What exactly do we mean by "branch"?) So let's just avoid the term by using what Git really uses: commit hash IDs.
When you run:
git checkout br2
you're telling Git to do two things:
save the name br2 for future use;
turn the name br2 into a commit hash ID, and extract—which includes "caring about"—a snapshot of all files from that commit.
The second step is the one that really matters right now: the first one is only needed later, when you run git commit to make a new commit, or some other Git command that needs the name (git branch or git status or git rebase, for instance).
With one exception—which you see in a fresh clone that hasn't yet run git checkout—Git always has some commit checked out right now. Your git checkout tells Git: sweep away the one we have right now, and get me some other commit as the checked-out commit.
Let's say that right now, you have br1 checked out, which is commit b100 right now. Later, the name br1 may mean some other commit, but right now it means that one. You run git checkout br2, which tells Git to switch from commit b100 to commit b200 as that's the one that the name br2 means right now.1
OK, no big deal yet, right? We're moving from commit b100 to commit b200. Commit b100 has in it the *.h files and omits the *.jpg files entirely. So Git "cares about" the *.h files while we have b100 out. Those files are tracked, which means they're in the (single) index. We're moving off b100 though, to b200, which has the *.jpg files and omits the *.h files. Git has to copy the *.jpg files into its index and remove the *.h files from its index, which means it has to remove the *.h files from your work-tree too.
So far, this is all going great: you get just what you want. But now you want to get to master and assemble the pieces. The name master means some other commit, maybe a123 at the moment.
No matter how you get to master, from br1 (b100 at the moment) or br2 (b200) at the moment, you don't have all the *.h and *.jpg files. You can only get one set or another. The underlying problem here is that the "caring about" happens because the files are in Git's index. Listing files in a .gitignore file, which is what you do to keep them from getting into Git's index, only helps if they're not already there—and when you switch to a commit that has the files, Git will put them into Git's index, regardless of what's in a .gitignore file. When you switch to a commit that omits the files, Git will remove them from Git's index, regardless of what's in a .gitignore file.
The index's contents reflect the commit you check out. Each commit has a full snapshot of every file that's in that commit. That snapshot winds up in Git's index. Unless you change them—with git add, or git rm, or by doing another git checkout that replaces them wholesale, for instance—those are the files that will go into the next commit.
Last, when you use git merge to combine work, Git:
finds a merge base commit;
compares the two branch tip commits against this merge base; and
uses that to figure out what to put into the new commit.
The new commit, like any commit, has a snapshot of all the files: all the files that were in Git's index at the time git merge made the merge commit, and those files are the result of the combining process above. Merge commits are the same as any other commit: they have a snapshot and metadata. The only thing that makes them special—makes them merge commits—is that they have two (or more) parent commit hash IDs listed in their metadata.
These interlocking behaviors get in the way: Either master actually does have all the files, in which case, the other commits found by other branch names also need to have all the files, or master doesn't have any of the files, in which case the other branches can be exclusive like this but you can't merge them back into master, because the common commit that Git will find, that will act as the merge base, will cause them to add the files to the new commit that goes into master—and now master has all the files! If you remove them as you go back into the branches, merging will remove the files this time.
Ultimately, Git is all about commits. It's the commits that determine, well, everything! The commits are snapshots-plus-metadata. All a branch name does is find one particular commit: the last one on some chain. Commits can be reached from more than one branch name, and many, or most, commits are on multiple branches simultaneously. So the name has nothing to do with which files are in the commit: it literally can't when more than one name finds that commit.
1Branch name to commit hash ID mappings change, which is how branches grow in Git. Git is built to add new commits, so the normal way that a name changes is that it now means a newer commit that leads, via the commit graph, back to the old commit—and many more commits too. See also Think Like (a) Git.

Cleaning up Main to Dev changesets

My Main branch seems to have change sets that my Dev branch does not have, but they are older. How should/can I clean up the changes sets?
The following is trying to merge Main into Dev and says there are changes. My understanding is that if Main and Dev match I should not see change sets during this merge anymore.
If I merge from Dev to Main I see no change sets.
Should I merge these even though newer change sets have already been applied? Example changes were made and merge into Main on 4/25.
Will this overwrite current code or will it really just update histories?
You could use tf merge command with /discard option.
/discard Does not perform the merge operation, but updates the merge
history to track that the merge occurred. This discards a changeset
from being used for a particular merge.
Sample command:
tf merge $/Project/SourceBranch $/Project/TargetBranch /discard /recursive /version:C56693~C56693
It discards changeset 56693. The version is a from ~ to, so you can discard multiple changesets at once. When the command has finished, you still need to check in the merge.

TFS Merge Specific Change Set - Change Set Missing

A google search and a specific stockoverflow search hasn't found me anyone else with this problem.
In tfs our procedures are that we make changes in a branch called Dev, than at a later time merge specific changesets up to a branch called DevQA. (We have other branches as well which shouldn't be affecting things at this point.) We use screens available in VS to do this.
I have 9 changesets which I made last week (all relating to the same or at least overlapping code) and it's now time to merge some of those up to DevQA.
The changes are showing in History on Dev, but when I choose merge, then specific change set (set the source to Dev and the target to DevQA) and click next the list of change sets available to merge does not include 7 of my 9 changes sets, including the ones I want to merge.
I've done some checks and they appear to be the only missing changesets, others have either been merged already, or are available in the list.
I have clicked on one of the changesets and used the 'track changeset' & Visualise options, and it shows the change set has NOT already been merged.
A new branch was created after these changesets were made, which was branched from DEV and my changesets show as being in that. However I don't believe this is related because other changesets which are in that ARE available to merge to DevQA.
Is there any reason these may not be showing up? Is there any way I can work around this and force them to merge?
If the changesets are in sequence or you don't mind to merge other changesets which in the range of your nine changesets, as a workaround you could try to use tf command.
Using the tf command line tool you specify a range of versions by separating the version with a tilde character.
tf merge /recursive /version:C1000~C1008 "$/SourceBranch" "$/TargetBranch"
In this case the changes 1000 and 1008 will also be included.
To merge multiple separate changesets into another branch you will have to do it in multiple steps:
tf merge /recursive /version:C1001~C1001 "$/SourceBranch" "$/TargetBranch"
Then your workspace for the target branch will contain the changes for both changesets and now you can check-in the merges as one changeset in the target branch.

Correctly merging a feature branch using TortoiseGit

I am learning to use Git, however, I'd like to keep a linear looking history. I have just finished my first feature branch.
I am now ready to merge it into my master branch.
I understand that the right way to do this is to rebase the feature branch or something and then merge it? Either way, there is some process for merging so that you retain commit history or something.
My main branch is called master. The feature branch is called import-publictalk-names.
Found this question:
Merging code branch to master using tortoisegit
So I think I have managed to do it correctly and this can be closed:
I think I have successfully done it now to my liking:
When you create a new branch you can basically work in parallel. However, whenever you merge (as described in https://stackoverflow.com/a/38203822/3906760) all changes from the feature branch are integrated into your current branch. At this point you have a synchronization point which somehow puts your changes into the history of your current branch (master). - Just in case a file is edited on both branches, there can be a conflict which needs to be resovled before an extra commit to finish the merge.
When you don't have an additional commit on your master branch (cf. Picture 1), a normal merge will result in a straight line which is not distiguishable from any commit which are on the master branch (the master branch label will just be assigned to the feature branch commit, cf. Picture 2). If you want to see a parallel line on the log which is optically merged into the master branch with a merge commit (a commit with has two parents instead of just one, cf. Picture 3), you need to enable the "No fast forward" merge option. - If there is a parallel commit on the master branch, you will always get a merge commit (unless you select "fast-forward only"). - Just as a side node: The files have all the the same content in picture 2 and 3, the only difference is in the meta-data in git.
Also, there are people who don't like that commits are visually interleaved as in your screenshot. From the git perspective normal merging is perfectly fine. But if you want to have a straigt line of commits, you need to rebase your feature branch on top of the branch into which you want to merge your changes (then you are in the case of Picture 1). After that merge the rebased branch (as fast-forward merge or non-fast-forward merge).
In order to make your history linear, "just" revert the merge by resetting master to the last commit (the parallel one, cf. Picture 4) with a "hard reset". Then checkout your feature branch and rebase it on top of master (click on the master branch in log dialog and click on "Rebase ... on this...". Then you have the case of Picture 1 and you can merge again.
Picture 1. Simple development on the reorder-commits branch with no parallel commits on master:
Picture 2. Merged reorder-commits into master with default options (i.e., fast-forward merge):
Picture 3. Merged reorder-commits into master with "non-fast-forward" option, note the merge commit with the "Merge branch ..." message and two parent commits:
Picture 4. Make the history linear again, by "reverting" your branch by (hard) resetting the master branch to its old position.

Revoking TFS Merge Credits

I understand that when performing a merge from BRANCHA > BRANCHB and selecting “Keep Target” on some files will result in “Merge Credits” being granted to those files in TFS history: Merging Developement Branch to Main: There were no changes to merge
Is there a way for us to revoke/wipe the Merge Credits on given files, effectively enabling our developers to perform a /force merge via Source Control Explorer?
Context:
On a weekly basis, we merge from BRANCHA > BRANCHB to synchronize parallel efforts. Any files with unresolved conflicts are noted and their owners are notified to perform a merge on those files from A > B. We then select “Keep Target” on these files – anticipating a future merge by the file owner to resolve the pending conflict. We’re delegating the work out to the individual owners.
This doesn’t quite work though, because TFS will see that the initial merge has “resolved” the conflict (basing its evaluation on prior merge history, not file contents).
I want to enable developers to perform re-merges on these files without forcing them to use the command prompt and /force switch.
Moving forward, my plan is to “Undo Changes” on those pending changes that were selected as “Keep Target” before checking in a branch>branch merge. This will enable the devs to perform the merges independently by dodging the merge credits.
But looking back, a branch<>branch /force merge results in hundreds of conflicts that we would like to delegate out to the owners as a means of syncing up two branches. Performing a classic merge reports nothing on these because prior merges have “Kept Target”.
You're indeed better off undoing the merge for the specific files you don't want to merge right now, but once you've chosen keep target, TFS indeed remembers that choice.
If you're already past the point of committing the merge, there is a way to get rid of the ticket, and that is to roll back the merge. You can roll back the merge for a group of individual files.
The trick here is as follows:
Look up each file and them in the Source Control Explorer.
Right-click the individual file and from the context menu choose to Rollback....
Enter the changeset number of the merge
Repeat 1 to 3 until you have all the file in your list.
Check-in this compensating changeset.
Try merging Branch A to Branch B again, your candidate changes should show up again.
You can do the same thing from the commandline, using tf rollback (pre-2015) or tf vc rollback (post-20215)

Resources