-
Notifications
You must be signed in to change notification settings - Fork 717
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix handling of renamed branches for clone/fetch #1493
Conversation
branch commits that are renaming, as rename destinations will have these. In GitTfsRemote.InitTfsRemoteOfChangeset(), when iterating over branch ancestry, call InitBranch() on the ancestor branch, not the target branch. Also only request fetching of parents for the most distant ancestor. Also when handling renamed branches, assign the renameResult for successors. In GitTfsRemote.InitTfsBranch(), pull the initial commit hash out of renameResult, if provided.
Just checked this on my case and it seems to work 😊👍 My case is a bit different to yours, though:
@dh2i-sam do you use the I will try to find and test the gitignore support on a simpler case that doesn't contain a merge from branch with different root, but do worry such scenario might even fail completely 🤔 |
@dh2i-sam Thanks for the PR. |
src/GitTfs/Core/GitTfsRemote.cs
Outdated
@@ -637,10 +647,12 @@ private IGitTfsRemote InitTfsRemoteOfChangeset(IBranchObject tfsBranch, int pare | |||
var branchesDatas = Tfs.GetRootChangesetForBranch(tfsBranch.Path, parentChangesetId); | |||
|
|||
IGitTfsRemote remote = null; | |||
bool first = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer a better name for the first
variable: isFirstBranchChangeset
? (or something better)
src/GitTfs/Core/GitTfsRemote.cs
Outdated
if (lastFetch != null && | ||
lastFetch.IsProcessingRenameChangeset) | ||
renameResult = lastFetch; | ||
else | ||
renameResult = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ternary operator?
if (lastFetch != null && | |
lastFetch.IsProcessingRenameChangeset) | |
renameResult = lastFetch; | |
else | |
renameResult = null; | |
renameResult = lastFetch?.IsProcessingRenameChangeset | |
? lastFetch | |
: null; |
src/GitTfs/Core/GitTfsRemote.cs
Outdated
if (renameResult != null && | ||
renameResult.IsProcessingRenameChangeset) | ||
sha1RootCommit = renameResult.LastParentCommitBeforeRename; | ||
else | ||
sha1RootCommit = Repository.FindCommitHashByChangesetId(rootChangesetId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
if (renameResult != null && | |
renameResult.IsProcessingRenameChangeset) | |
sha1RootCommit = renameResult.LastParentCommitBeforeRename; | |
else | |
sha1RootCommit = Repository.FindCommitHashByChangesetId(rootChangesetId); | |
sha1RootCommit = renameResult?.IsProcessingRenameChangeset | |
? renameResult.LastParentCommitBeforeRename; | |
: Repository.FindCommitHashByChangesetId(rootChangesetId); |
About the The Add .gitignore commit should be a parent of Add $/Proj/B1/File branch. Or at least should be there for every branch that has no parent, or else a Btw, I've tried running this change against a simpler TFVC branch history but had no luck - the rename wasn't followed. I'm just about debugging it right now, so will get back with my findings :) |
So I'm debugging and I have this basically:
and I use the @dh2i-sam how do you invoke git-tfs? I use this:
All in all, I think I know what to do in order to maybe fix both the gitignore and this not working for me issues. Will play with it a bit and get back 🙂 |
Well basically I think the issue with the aforementioned scenario is simply that the original branch does not exist in the Git repo yet. It would be fine if the first changeset in It would all maybe work if there was the history of the original branch in the Git repo already and then we asked git-tfs to fetch the branch from the new location. |
Let's say we have the following structure:
Cloned using:
The above starts fetching To fix this we first have to detect that the I was looking into that a bit yesterday. There is an |
I got some time to look at this today and managed to get the value of |
So I found a method VersionControlServer.GetBranchHistory(new[] { new ItemSpec("$/Project/RenamedBranch", RecursionType.None) }, VersionSpec.Latest) Returns a structure like (simplified a lot):
with all other branches ever created from the descendants of the original So maybe I will use that - when starting the clone, will use this to find the oldest branch and work bottom-up, following all renames and everything. |
Just wanted to pitch in to comment that this PR fixed a problem with a customer TFS library I was having because of a large number of branches the customer had renamed. Built @dh2i-sam's repo and ran using that git-tfs.exe and went from the clone of their whole repo going from taking 9.5 hours and having several orphaned branches and merge changesets being treated as having no parent branch to a perfectly run clone that finished in just under 2 hours. |
@bj185066 hi,can you please show me the command you ran this tool with? I haven't had such luck, unfortunately, so I built other changes on top of these (and will submit a PR hopefully this or next week) to fix my use case but I really wonder what do you do differently that it works for you 😁 Or whether it's just the way the TFS repo was used... |
My command (stripped of customer specifics) was as follows The short explanation on the ignore regex is that there are merges to the customer's repos from our main repos that they don't have read access to anymore by their customer agreement, so we're skipping those branches. Everything else we want. The general layout along the problem areas was as follows
Every time it would hit those, it was able to successfully get the branch and rename commit on |
Thanks a lot @bj185066!! That's what I thought, you go bottom-up so to say - you tell git-tfs to clone the original location, not the new one as I do. I haven't tried this myself actually, but I always started with the renamed location, going up-to-bottom basically, so that's why these changes didn't work for me and why I developed on them further! Thanks a lot for clarification, though, I was really wondering if I'm just missing something here 😅 |
Thanks @bj185066 and @bramborman for your feedback that helps me evaluate the value of this PR. I was waiting for @dh2i-sam feedback on code review few nit-pickings but we get no feedback ( @dh2i-sam ?) |
Agree on merging, but please don't close the related issues as they are imho not completely solved - depends on how you clone and I have a fix for that locally :) |
I was not planning to do it but thanks for the head up: I will be careful about what GitHub will do automatically... |
Thanks all. |
The bug that this is intended to fix appears to be documented in #1029. I've been trying to migrate a TFS repository to Git, and need complete history. My repository has maybe five branches that have been renamed, and I've lost patience with working around this bug by manually initializing remotes of the deleted former branch names to ensure that preceding changesets are present, as well as manually enumerating all of the branches.
The fix has three facets:
In GitTfsRemote.FetchWithMerge(), apply special handling to initial branch commits that are renaming, as rename destination branches will have these.
In GitTfsRemote.InitTfsRemoteOfChangeset(), when iterating over branch ancestry, call InitBranch() on the ancestor branch path, not the target branch path. Also only request fetching of parents for the most distant ancestor. Also when handling renamed branches, set the renameResult parameter for the successor.
In GitTfsRemote.InitTfsBranch(), pull the initial commit ID out of renameResult, if provided.