Here is the issue on GitTfs about some complexities in usage. The point is GitTfs allows you to take a feature branch and put it into the TFS in single checkin. On the git side this action produces merge commit with two parents: one for previous commit fetched from TFS and another from your feature branch. If you want to have fine-grained history on TFS side – you have a problem.
So what could we do with it?
I’ve just finished a patch that allows to perform fine-grained workflow more-or-less painlessly. The idea is new option to checkin command, namely –rebase-workflow or just -r.
Lets name for simplicity commit being checked into TFS as ‘source’ and fetched afterwards as ‘result’. Source belongs to feature branch that we want to check into TFS commit-by-commit.
So what -r key is supposed to do? First and the most important result of -r is that it suppresses marking result as merge commit. Just skips assigning source as parent. So after checkin we’ll have two separate branches, and result will actually contain all changes from source but it won’t be shown in the graph.
See the diagrams below:
A [tfs] \ \<-- B <--- C
A <----- B' \ [tfs] \ \<-- B <--- C
Here B’ has all changes from B.
Just to compare with default behavior:
[tfs] A <---------- M \ / \ / \<-- B <----- C
M is merge commit and B is original. They are just the same change from A most of the time and it is confuses history very much.
So how could we going to turn two diverging branches into linear history? With a rebase of course.
We could take remaining of the local branch (so it is C actually) and rebase it to the B’. It will go smoothly as we are just applying clean patch essentially. Thus B becomes (most likely – if there were no third branches spawned from feature branch) orphan commit and will go away. Which is ok as we have all changes from it in the B’. And it is exactly what -r key tries to do for you.
I did some testing (simplest actually and with some conflicts/interfering with native TFS client) on my local TFS server and it seems working well and producing much more understandable history. But I’m not an expert in git so I could miss some cases. Currently I only check with rev-list that source doesn’t have parents which are not parents of HEAD thus we could apply source..HEAD to result smoothly.
Intended workflow is like that:
git checkout -b local # make changes git commit -m 'blah' # make changes git commit -m 'blah2' git tfs fetch git rebase tfs/default git tfs checkin -r -m 'blah goes to tfs with rebase' HEAD^ # thus we are sending just first commit leaving history clean git tfs checkin -r -m 'blah2 goes to tfs also' # here source is HEAD so we can omit it git checkout master git merge tfs/default git branch -D local
As a result you should have just a linear history in git consisting from TFS commits.
So the comments/objections/suggestions are welcome.
Branch with corresponding changes is here
UPDATE: currently rebase-workflow branch is integrated in mainline of the git-tfs project in form of rcheckin command. So the branch mentioned above is no longer exist.