I have to modify a faulty program/feature, which is an extension to org.eclipse.jgit
the program overrides the close method of the PushResultDialog and passes the Repository to an method.
Here i want to find the branch which was actually pushed/checked out. I am only interested if its the master, if not i don't wanna do anything.
else i need the list of the pushed files.
First the program looked like this :
head = repo.resolve(Constants.HEAD);
RevCommit commit = rw.parseCommit(head);
PersonIdent committerIdent = commit.getCommitterIdent();
sCommitter = committerIdent.getName();
String sBranch = "?";
for (Map.Entry<String, Ref> e : repo.getAllRefs().entrySet()) {
if (e.getKey().startsWith(Constants.R_HEADS)) {
Ref ref = e.getValue();
if (rw.isMergedInto(commit, rw.parseCommit(ref.getObjectId()))) {
sTemp = ref.getName();
int i = sTemp.lastIndexOf('/');
if (i == -1)
continue;
sBranch = sTemp.substring(i + 1);
System.out.println("Ref " + sBranch
+ " < contains > " + commit);
if (sBranch.equalsIgnoreCase("master")) {
break;
} else {
return;
}
}
}
}
RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
DiffFormatter df = new DiffFormatter(
DisabledOutputStream.INSTANCE);
df.setRepository(repo);
df.setDiffComparator(RawTextComparator.DEFAULT);
df.setDetectRenames(true);
List<DiffEntry> diffs = df.scan(parent.getTree(),
commit.getTree());
for (DiffEntry diff : diffs) {
sTemp = diff.getNewPath();
pushedObjects.add(sTemp);
}
now .. this works as long as the workflow in eclipse is just "checkout master" "pull" "merge branch" "push"
any other order seems to mess with the order of the branches in the set, and it stumbles over this "else" :
if (sBranch.equalsIgnoreCase("master")) {
break;
} else {
return;
}
the question is : is there an eaasy method to pick the right branch?
Ok, i think i can simply look at the HEAD in the set:
e.getKey().startsWith(Constants.HEAD)
and then parse the branchname, that should always be the branch which is checked out, if (in my case),if it is the master, i am happy.
Related
I am trying to access the full repository history of an IFile object programatically from an Eclipse plugin. When the file has never been renamed or moved, the following code snippet works:
public long getFileHistoryTimestamp(IFile file, IProgressMonitor monitor, boolean lastModified) {
IProject project = file.getProject();
RepositoryProvider rProv = RepositoryProvider.getProvider(project);
long createdMillis, lastModifiedMillis;
if (rProv !=null) {
IFileHistoryProvider fhp = rProv.getFileHistoryProvider();
if (fhp != null) {
IFileHistory fHist = fhp.getFileHistoryFor((IResource) file,
IFileHistoryProvider.NONE, null);
IFileRevision[] revs = fHist.getFileRevisions();
Arrays.sort(revs, new Comparator<IFileRevision>(){
public int compare(IFileRevision o1, IFileRevision o2) {
return Long.compare(o1.getTimestamp(), o2.getTimestamp());
}
});
for (IFileRevision rev : revs) {
if (rev.getTimestamp() >= 0) {
createdMillis = rev.getTimestamp();
break;
}
}
if (revs.length > 0) {
lastModifiedMillis = revs[revs.length - 1].getTimestamp();
}
}
return lastModified ? lastModifiedMillis : createdMillis;
}
But, if the file has been moved (e.g. with a multi-module maven project to a new or different module/project), then the values returned above are only for the file in it's current location - i.e. it does not track any rename/moves. The same file in the Eclipse Team History view does track the full version history.
How can I access this full history within the Eclipse Team API?
I'm moving our on premise tfs repositories to visualstudio online. In the process I'd prefer to convert everything to git.
I found this (*) post online and everything works. But now I would like to use libgit2sharp to amend all the comments so to point to the correct work items.
I've cobbled together a bit of code that should do the trick:
Dictionary<string,string> links; //contains all links between new and old workitems, keys: old workitems, values: new workitems
using (var repo = new Repository(#"D:\gittfs\testproject"))
{
foreach (var commit in repo.Commits)
{
var commitMessage = commit.Message;
var regex = new Regex(#"#[0-9]*");
foreach (Match match in regex.Matches(commitMessage))
{
string newId;
if (links.TryGetValue(match.ToString(), out newId))
{
commitMessage = commitMessage.Replace(match.ToString(), newId);
}
}
var c = repo.Commit(commitMessage, new CommitOptions { AmendPreviousCommit = true });
}
}
This code runs without a problem and if I compare c.Message with commit.Message, I can see several of these being replaced. The problem is that after the program has ran, none of the amended commits are in the repository. So I think I'm still doing something wrong?
(*)https://www.microsoft.com/en-gb/developers/articles/week02mar2014/migrating-a-tfs-tfvc-based-team-project-to-a-git-team-project-retaining-as-much-source-and-work-item-history-as-possible/
I think you might rather be after some git filter-branch like feature.
LibGit2Sharp exposes this through the HistoryRewriter type.
You can peek at the FilterBranchFixture test suite for inspiration.
following code did the trick for me. thnx nulltoken!
var rewriteHistoryOptions = new RewriteHistoryOptions()
{
CommitHeaderRewriter = commit =>
{
var commitMessage = commit.Message;
bool stuffreplaced = false;
var r = new Regex(#"#[0-9]*\ ");
foreach (Match match in r.Matches(commit.Message))
{
string value;
if (links.TryGetValue(match.ToString().TrimEnd(), out value))
{
commitMessage = commitMessage.Replace(match.ToString().Trim(), value);
Console.WriteLine(commit.Id + ": " + match.ToString() + " replaced by " + value);
stuffreplaced = true;
counter++;
}
}
if (stuffreplaced)
{
return CommitRewriteInfo.From(commit, message: commitMessage);
}
else
{
return CommitRewriteInfo.From(commit);
}
}
};
repo.Refs.RewriteHistory(rewriteHistoryOptions, repo.Commits);
We're a fairly large project with a single trunk branch. Most of it uses the default permissions, but a few folders have custom permissions - say, only "Builders" group is allowed to check-in.
We want to allow people to create their own private branches out of trunk, where they can freely check-in and merge later (hopefully often). However, creating a branch, the special permissions are copied along with the folders, meaning that people can't freely check-in into their branch.
Is there a way to clear special permissions from a branch, or a folder?
Is there a way to do so automatically, so anyone creating a branch under /private/** will not encounter this problem?
I found out about tf permission (Example: tf permission /inherit:yes itemSpec). However, the /recursive switch doesn't work with it. I guess I could write something that runs it recursively...
Edit: I finally got around to writing a tool for it:
static int Main(string[] args)
{
if (args.Length == 0 || args.Any(a => !a.StartsWith("$/")))
{
Console.WriteLine("Removes all explicit permissions and enables inheritance for a subtree.\n"
+ "Example: " + Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location) + " $/project/path1 $/project/path2");
return 3;
}
WorkspaceInfo wi = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
if (wi == null)
{
Console.WriteLine("Can't determine workspace for current directory: " + Environment.CurrentDirectory);
return 2;
}
var Tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wi.ServerUri);
VersionControlServer VersionControlServer = Tfs.GetService<VersionControlServer>();
Console.WriteLine("Server: {0} Getting permissions...", wi.ServerUri);
ItemSecurity[] perms = VersionControlServer.GetPermissions(args, RecursionType.Full);
Console.WriteLine("Will remove explicit permissions from the following items:");
var changes = new List<SecurityChange>();
foreach (ItemSecurity perm in perms)
{
Console.WriteLine(" " + perm.ServerItem);
changes.Add(new InheritanceChange(perm.ServerItem, inherit: true));
foreach (AccessEntry e in perm.Entries)
{
changes.Add(new PermissionChange(perm.ServerItem, e.IdentityName, null, null, PermissionChange.AllItemPermissions));
}
}
Console.WriteLine("Enter to confirm:");
Console.ReadLine();
var successfulchanges = VersionControlServer.SetPermissions(changes.ToArray());
if (successfulchanges.Length == changes.Count)
{
Console.WriteLine("Explicit permissions removed from all items");
return 0;
}
else
{
Console.WriteLine("Explicit permissions removed only from:");
foreach (var c in successfulchanges)
{
Console.WriteLine(" " + c.Item);
}
return 1;
}
}
We've been using mercurial for a while now and everything is working fine.
The only problem we encounter is when someone runs a "bad command".
An example would be, merging an unstable branch in the stable trunk or pulling a similarly named branch over something completely unrelated overwriting a bunch of stuff...
You've got hg log but you always get people that won't believe the output saying "I didn't do that"...now in the interest of public shaming :) and giving rightful priviledges to the "You broke the built hat", I'm wondering, is there a way to have Mercurial log every command its given to a text file that would give us something like:
hg pull -b something
hg merge TotallyWrongBranch
hg ci -m "I didn't do it!" -u bsimpson
Ok, I had a few minutes on my hand so I wrote an exe and named it hg.exe and renamed Mercurial's original exe to real_hg...
An ugly hack don't mind the code quality please IT WORKS!
public static StreamWriter sw;
static void Main(string[] args)
{
sw = new StreamWriter("hgCommandLog.txt", true);
StringBuilder sbArguments = new StringBuilder();
if (args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
sbArguments.Append(args[i]);
sbArguments.Append(" ");
}
}
//Console.WriteLine("arg:" + sbArguments.ToString());
//Console.WriteLine("Session ID = " + System.Diagnostics.Process.GetCurrentProcess().SessionId.ToString());
//Console.WriteLine("hello ->"+Environment.GetEnvironmentVariable("CLIENTNAME"));
string sessionID = System.Diagnostics.Process.GetCurrentProcess().SessionId.ToString();
string clientName = Environment.GetEnvironmentVariable("CLIENTNAME");
//log the command to sw
sw.WriteLine(DateTime.Now.ToString() + "\t" + clientName + "("+sessionID+")\t" + "hg " + sbArguments.ToString());
sw.Flush();
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "real_hg";
p.StartInfo.Arguments = sbArguments.ToString();
p.StartInfo.CreateNoWindow = true;
p.ErrorDataReceived += outputReceived;
p.OutputDataReceived += outputReceived;
p.EnableRaisingEvents = true;
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
p.BeginOutputReadLine();
//p.BeginErrorReadLine();
p.WaitForExit();
sw.Close();
}
static void outputReceived(object sender, DataReceivedEventArgs e)
{
sw.WriteLine("\t"+e.Data);
Console.WriteLine(e.Data);
}
Is there any CVS command that can give me previous revision of a file, given the filename and its revision?
The way CVS controls the version of a file is that the revision is increased only when there is a commit in that file. The changes in the tree or tagging etc will not affect the revision of a single file.
Although there is no definite way of getting the previous revision of a file, given the name and it's revision... But there is a hit and trial method around it. Blindly go to the previous revision. For eg, the prev revision of Rev 1.5 would be Rev 1.4
Another way to sort this out is, to write a shell script. Use cvs log to get the change log of a particular filename and grep the desired revision number.
There is no direct way to do this from CVS commands. But since I am using the output (of CVS log) IN java, following code snippet worked for me
if (currentRevision == null || currentRevision.trim().length() == 0) {
return null;
}
String[] revComponents = currentRevision.trim().split("\\.");
if (revComponents == null || revComponents.length == 0) {
log.warn("Failed to parse revision number: " + currentRevision
+ " for identification of previous revision");
return null;
}
if (revComponents.length % 2 == 1) {
log.warn("Odd number of components in revision: " + currentRevision);
log.warn("Possibly a tag revision.");
return null;
}
int lastComp;
try {
lastComp = Integer.parseInt(revComponents[revComponents.length - 1]);
} catch (NumberFormatException nmfe) {
log.warn("Failed to parse the last component of revision from " + currentRevision);
log.warn("Identified presence of alphanumric values in the last component. Cannot predict previous revision for this");
return null;
}
if (revComponents.length == 2 && lastComp == 1) {
log.debug("Revision: " + currentRevision + " is the first revision for the current file. Cannot go further back");
return null;
}
StringBuilder result = new StringBuilder();
if (lastComp == 1) {
for (int i = 0; i < revComponents.length - 2; i++) {
if (result.length() > 0)
result.append('.');
result.append(revComponents[i]);
}
} else if (lastComp > 1) {
for (int i = 0; i < revComponents.length - 1; i++) {
result.append(revComponents[i]);
result.append('.');
}
result.append((lastComp - 1));
} else {
log.warn("Found invalid value for last revision number component in " + currentRevision);
return null;
}
return result.toString();
}
Above code also handles branch revisions, for example, if the current revision (in picture) is the first one on branch that it will return the revision from which branch for that file was created.
Hope this helps.