Skip to content
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

[Waiting Review] Improvements in Tfs branches support #480

Merged
merged 50 commits into from Jul 10, 2014

Conversation

pmiossec
Copy link
Member

@pmiossec pmiossec commented Nov 4, 2013

This pull request bring bing improvements in TFS branch support:

  • auto initialization of a tfs branch, if needed, and fetching needed changesets when encountering a merge changeset to be able to create the merge commit with its 2 parents (default behavior). See image below...
  • tfs branch renaming
  • baseless merge (when the merge changeset was a merge of a branch without the same base as the trunk branch)
  • add a --ignore-branches option to ignore merge changeset and process it as a normal changeset (for those that can't manage branches due to a messy tfs repository).

git-tfs_branches
If I clone tfs/default (git tfs clone https://tfs.codeplex.com:443/tfs/TFS16 $/vtccds/trunk) and it encounter a merge changeset, it create and fetch automatically the branch tfs/b1 to be able to create the merge commit.

@KindDragon
Copy link
Contributor

What missing in this PR? When you plan merge it?
I really want this feature.

@KindDragon
Copy link
Contributor

Maybe support only simple renaming branch at start and baseless merge?

@pmiossec
Copy link
Member Author

pmiossec commented Feb 3, 2014

I have worked on that yesterday after quite some long time without having time to do it :(
I have rebased my work onto master and corrected the 5 unit tests that failed since a long time...

What I need before merging this pull request is a good code review, doing some test on different scenarii (I have only tested with --with-branches option and need to be sure to not have broken something when you don't use it) and some (successful) tests by other user.

Did you have tested it successfully yourself? Does that solve cases where released git-tfs failed?

@KindDragon
Copy link
Contributor

Now I try to merge this branch with my to check it out.

@pmiossec
Copy link
Member Author

pmiossec commented Feb 3, 2014

Maybe support only simple renaming branch at start and baseless merge?

I'm not sure I want to do that. It's perhaps what I should have done in the beginning but things are too intricate and I'm not sure I will be able to merge them one by one without lot of works! :(

@pmiossec
Copy link
Member Author

pmiossec commented Feb 5, 2014

@KindDragon I successfully manage the last point I want to be solved before trying to merge the PR.
Need some more work to do it well, some history cleaning, perhaps some code review and we will be ok...

@KindDragon
Copy link
Contributor

👍 👍 👍

@pmiossec
Copy link
Member Author

pmiossec commented Feb 6, 2014

@spraints @sc68cal @KindDragon
It's no more a work in progress! It's time to review \o/
I will try to say more about this PR tomorrow when my laptop battery will not be empty anymore...

@@ -64,6 +65,9 @@ public int Run(string tfsUrl, string tfsRepositoryPath, string gitRepositoryPath

VerifyTfsPathToClone(tfsRepositoryPath);

if (withBranches && initBranch != null)
fetch.IgnoreBranches = false;

if (retVal == 0) fetch.Run(withBranches);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think branch --init --all should work almost identical as clone --with-branches.
Maybe we shouldn't call fetch if withBranches == true?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm... Need some explanation... ;)
branch --init --all and clone --with-branches couldn't work as identical as because the branch command could only be used in an already initialized repository.
Except from that, with this PR, they do the same thing! \o/
you could do:

  • init + branch --init --all
  • clone + branch --init --all
  • clone --with-branches
    and you will end up with the same repo!

Maybe we shouldn't call fetch if withBranches == true?

No, must keep the way it works. clone is init + fetch. If we remove fetch what is remaining? And I don't really understand why you want to condition fetch call...

           if (withBranches && initBranch != null)
               fetch.IgnoreBranches = false;

That's just a security to prevent use of --with-branches and --ignore-branches that are 2 options incompatibles.
--ignore-branches is an option to keep the way git-tfs actually works for those where the TFS repository is a mess and can't support branches.

withBranches is an option to the fetch command to tell it to do special things to support branches when fetching. So it's OK...

To conclude, all is OK, like that! I have tested and approved!! ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, must keep the way it works. clone is init + fetch. If we remove fetch what is remaining? And I don't really understand why you want to condition fetch call...

Clone call after Fetch - InitBranch.Run() if withBranch = true. I thought it will fetch all branches?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I understand! you're right, we can remove the call to the fetch because after we call initBranch.Run() now that the pull request manage branch initialization "on the fly".
But I'm not sure I will remove this call. Because if you've got a problem in the initBranch call, there is more chance that you've got your main branch fetched... I don't know....

@pmiossec
Copy link
Member Author

pmiossec commented Feb 8, 2014

I will try to say more about this PR tomorrow when my laptop battery will not be empty anymore...

I have updated the PR description with what this PR is doing...

@pmiossec
Copy link
Member Author

GetRootChangesetForBranch produce stack overflow when UPPER_CASE_BRANCH renamed to lower_case_branch

I have included your 2 commits in the PR. Is the problem solved by the remove of the 2 .ToLower()? Or does that still need to be investigated?

@KindDragon
Copy link
Contributor

I cannot reproduce bug anymore

@KindDragon
Copy link
Contributor

@pmiossec How to clone a single branch with all parent branches and branches that have been merged into this branch?

@pmiossec
Copy link
Member Author

With this PR, if that's the trunk branch that you clone, that's done
automatically when doing

git tfs clone http://yourserver $/yourproject/yourtrunk

If that's not the trunk that you want to clone, that's not supported for
the moment and you will end with the branch starting from where it has been
branched from the parent branch. Perhaps the merged branches will be
initialized but I can't guarantee it...
On 14 Feb 2014 16:30, "Arkadiy Shapkin" notifications@github.com wrote:

@pmiossec https://github.com/pmiossec How to clone a single branch with
all parent branches and branches that have been merged into this branch?

Reply to this email directly or view it on GitHubhttps://github.com//pull/480#issuecomment-35093348
.

@theyeag
Copy link

theyeag commented Feb 22, 2014

I'm testing this build and it looks like the code is causing a loop.

My command: git-tfs.exe clone --with-branches http://tfs:port/tfs/project $/project/rootBranch NewProjectName

Output

Branches to Initialize successively :
-$/project/serviceBranch (6580)
=> Working on TFS branch : $/project/branch/
Fetching from dependent TFS remote Dev...
Fetching from dependent TFS remote branch/branch1...
etc...
Branches to Initialize successively :
-$/project/serviceBranch (6580)
=> Working on TFS branch : $/project/branch/
Fetching from dependent TFS remote Dev...
Fetching from dependent TFS remote branch/branch1...
etc...

This was looping for about a 1 1/2 days with both tests.

Is there anything I can do to help debug this?

@pmiossec
Copy link
Member Author

@theyeag your log is a little light ;) but I think (and I hope) I know where your problem come from...

I will update this pull request with a correction but the bad news is that you end in a loop because git-tfs was unable to initialized a branch. I think that it was unable to find the root changeset of the branch :(

@theyeag
Copy link

theyeag commented Feb 22, 2014

Ha, I was trying to get it down to the bare minimum. I hate diving through useless information so I try to save others where I can :). I have a guess to what may have caused this.
I made some baseless merges and deletions to reparent a branch from Main -> Dev -> Branch to Main -> Dev -> Branch -> SubBranch.

Let me know if I can provide any logs, tests, or examples. I'm digging into the code but my C# is a little rusty. It may be a bit before I'm much use.

@pmiossec
Copy link
Member Author

@theyeag here is a new version. I hope it will solve the problem of the loop and better know why one of your branch couldn't be initialized...

I made some baseless merges and deletions to reparent a branch

Basless merge should be supported and deletion too (but perhaps not all cases possible)...

@@ -33,13 +33,24 @@ public LogEntry Apply(string lastCommit, IGitTreeModifier treeBuilder, ITfsWorks
var resolver = new PathResolver(Summary.Remote, initialTree);
var sieve = new ChangeSieve(_changeset, resolver);
workspace.Get(_changeset.ChangesetId, sieve.GetChangesToFetch());
foreach (var change in sieve.GetChangesToApply())
var changes = sieve.GetChangesToApply().ToList();
if (!IsRenameChangeset(changes, workspace.Remote.TfsRepositoryPath))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a really broad exclusion. I read it as "skip any changeset that has a deleted item outside of the directory I'm working in." I'm concerned that a changeset with changes like this:

  • Edit $/Project/FileICareAbout.cs
  • Delete $/OtherProject/FileIDoNotCareAbout.cs

will get skipped.

Also, I'd really prefer that logic like IsRenameChangeset lives in ChangeSieve so that it can be covered more easily by unit tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

....and then prevent all the delete when the changeset is a renamed changeset!

I will have a look at how to solve that in a better way....

@spraints
Copy link
Member

@pmiossec - ❤️ This looks like a pretty awesome improvement!
@KindDragon and @theyeag - thanks for your work on this!

Other than the inline comments, can you

@KindDragon
Copy link
Contributor

@pmiossec Clone trunk crash for me in that line KindDragon@494b56e

@pmiossec
Copy link
Member Author

@KindDragon I have cherry-picked your commit but if you end here, I think there is a case that is not well managed by the PR :(

And I am interested by knowing what is this case. Delete branch? something else?

@KindDragon
Copy link
Contributor

I will try reproduce this issue again

@pmiossec
Copy link
Member Author

pmiossec commented Jul 8, 2014

I plan to merge that very soon (one or two days) and continue building on top except if someone yell against it...

It was waiting too long!

cc @spraints @KindDragon

pmiossec added a commit that referenced this pull request Jul 10, 2014
[Waiting Review] Improvements in Tfs branches support
@pmiossec pmiossec merged commit ee86eed into git-tfs:master Jul 10, 2014
@KindDragon
Copy link
Contributor

@pmiossec I think we should change git-tfs pull default behavior for old repositories, it shouldn't initialize new branches automatically or it's break current git-tfs workflow in my company.

Maybe made ignore-not-init-branches = true for old repositories

@pmiossec pmiossec deleted the rename_branch branch July 13, 2014 20:55
@pmiossec
Copy link
Member Author

Perhaps you're right. I'll think about that. How to change that. Perhaps we will have to change the state of the internal parameter...

@KindDragon
Copy link
Contributor

Or maybe merge options ignore-branches and ignore-not-init-branches to one with 3 states:

  1. Fetch all merged branches (default for new repositories)
  2. Fetch only initialized merged branches (default for old repositories)
  3. Don't fetch merged branches

@spraints
Copy link
Member

I plan to merge that very soon (one or two days) and continue building on top except if someone yell against it...

It was waiting too long!

🙇 Thanks for your patience, I think this is a good time to have merged this.

@StephenHurn
Copy link

Unfortunately I have been having some trouble using this feature.

I have a convoluted branch/merge heirarchy on the TFS server that I am attempting to pull from.

Project A branches to a subfolder of Project B and H
Project B branches to a subfolder of Project C, D and H
Project C branches to a subfolder of E, F, G and H
Project F branches to project H

I want Project F and project H

Unfortunately I don't seem to be able to clone F, with H as a branch without also having git-tfs attempt to clone A, B and C. The --ignore-branches switch does not seem to work with --with-branches.

My goal: I want to clone a TFS repository and one of the branches that originated from this repository.
What was happening: I got hit by the rename bug and could not initialize the new branch.
What is happening now: I can now initialize the new branch, but not without also initializing every other branch that this new branch has ever had a merge changeset from.

There could be a couple of solutions to this problem:

  1. git tfs branch could implement an --ignore-branches option
  2. git tfs clone could allow the user to specify which branches to initialize during the clone (--with-branch=VALUE)

Unless I'm missing something?

@StephenHurn
Copy link

Ok it turns out that I was missing something.

I achieved my goal by doing the following:

  1. Cloning using the --ignore-branches option.
  2. run the command "git config git-tfs.ignore-not-init-branches "true""
  3. Init the branch

Comment on lines +486 to +488
private string FindMergedRemoteAndFetch(int parentChangesetId, bool stopOnFailMergeCommit, out string omittedParentBranch)
{
var tfsRemotes = FindTfsRemoteOfChangeset(Tfs.GetChangeset(parentChangesetId));
foreach (var tfsRemote in tfsRemotes.Where(r=>string.Compare(r.TfsRepositoryPath, this.TfsRepositoryPath, StringComparison.InvariantCultureIgnoreCase) != 0))
return FindRemoteAndFetch(parentChangesetId, false, true, out omittedParentBranch);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stopOnFailMergeCommit parameter is unused and false is passed to the stopOnFailMergeCommit parameter of the called method. Should it be fixed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's always good to clean the mess 😉

Could you do a PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants