The problem is that the complex merge history in TFS is difficult. Simply put, git commits can have multiple parents, while a set of TFS changes can have only one.
Consider the state in which my git repository has HEAD with some commit, say 9c42ef... Now I make the changes and commit them, creating a new commit 1f23cd... Meanwhile, I also accept the changes from Bob, who was also commit based on 9c42ef... Its change is commit ID f41ac3... If I want to enable both changes, I will need to merge, and I will say that ultimately with the identifier commit ID 7acdfe... Your chart now looks like this:
1f23cd / \ 9c42ef 7acdfe (HEAD) \ / f41ac3
This cannot be easily represented in TFS, since there can only be one ancestor in a single set of changes (the set of changes immediately before it). Therefore, we need to linearize the story. This is why the --squash and --auto-squash exist on git-tf checkin (with deep control).
The --squash allows you to choose which path to follow when going through the story. For instance:
git-tf checkin
Omitting f41ac3 , walking along the schedule, you will have three sets of changes, the contents of 9c42ef , 1f23cd and 7acdfe . But on a large chart, it's a lot of work to indicate every commit for squash. In this case, --auto-squash will use magic to determine which path to follow. (He prefers the path with the longest chain of commits, so you get the longest history, and if the two segments are the same length, they will use timestamps to determine which path to follow.)
git-tf checkin --deep --auto-squash
You can also repack, so the commits you checked were linear, and each of them had only one parent.
git-tf developers use each of these strategies depending on the complexity of the tree, masochistic feelings about a set of endless lines of SHA1 hashes, and the moon phase.