Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git-tf checkin fails: commit [commitid] has multiple parents. Using --deep option to create history in TFS

It appears that neither --deep or --shallow seem to work. I am getting an error when attempting to do a git-tf checkin --deep to a new folder (currently empty) in TFS. I have a git repo with quite a bit of history. I would love to keep/migrate to TFS as part of git-tf.

My understanding is that the checkin --deep would create an analogous changeset in TFS for each commit. The problem is that any commit in the git repo that appears to have been the result of a merge (and we have many merges in this repo) seems to make the git-tf command very unhappy and reports the error message I mentioned in the title (with the exception of the [commitid] is replaced with a real commit id (e.g. 9a26d8)).

I'm not sure if I'm totally missing the boat here or what. Is there a reliable way to port a pre-existing git repo with multiple merges commits in history to TFS? I expected this to be a primitive feature/fix. I hope I am missing something. I am very saavy with TFS, but not as seasoned with git so any help is appreciated.

like image 409
EdFred Avatar asked Dec 04 '22 14:12

EdFred


1 Answers

The problem here is that representing a complex merge history in TFS is difficult. Quite simply, git commits can have multiple parents, whereas a TFS changeset can only have one.

Consider the state where my git repository has HEAD at some commit, let's say 9c42ef.... Now I make a change and commit it, creating a new commit 1f23cd.... Meanwhile, I also take a change from Bob, which was also a commit based on 9c42ef.... His change is commit ID f41ac3.... If I want to incorporate both changes, I'll have to do a merge, and let's say I end up with commit ID 7acdfe.... Now your graph looks like this:

          1f23cd
        /        \
9c42ef             7acdfe (HEAD)
        \        /
          f41ac3

This can't be easily represented in TFS since a single changeset can only have one ancestor (the changeset directly preceding it.) So we need to linearize history. This is why the --squash and --auto-squash options exists on git-tf checkin (when doing a deep checkin).

The --squash option allows you to select which path to follow when working its way through history. For example:

git-tf checkin --deep --squash f41ac3

Will omit f41ac3 when walking the graph and you will have three changesets, the contents of 9c42ef, 1f23cd and 7acdfe. But in a big graph, this is a lot of work to specify each commit to squash. In that case, --auto-squash will use some magic to determine which path to follow. (It prefers the path with the longest chain of commits so that you get the most history possible and if two segments are of equal length, will use timestamps to determine which path to follow.)

git-tf checkin --deep --auto-squash

You could also rebase such that the commits you were checking in were linear and each had only a single parent.

The git-tf developers use each of these strategies depending on the complexity of the tree, masochistic feelings about typing endless strings of SHA1 hashes and the phase of the moon.

like image 195
Edward Thomson Avatar answered Dec 08 '22 14:12

Edward Thomson