How to force merge (with conflict markers) in JGit? - merge

Our application needs to use different merge strategies when fetching / merging with JGit. For instance, for any files in conflict that are JSON files, we want to revert any local changes and get THEIRS. If they're not JSON files, we want to keep local changes and merge, even keeping the conflict markers if there are conflicts. However, no matter how I set the merge strategy, I get a CheckoutConflictException (which stops the merge) even if normal command-line git would have done the merge. What am I doing wrong?
public String update() throws Exception {
// We fetch manually and do a dry-run merge to catch any conflicts, so we can reset them
fetch();
Ref fetchHead = this.repo().getRepository().findRef("FETCH_HEAD");
try {
MergeResult mergeResult = this.repo().merge()
.setStrategy(MergeStrategy.RECURSIVE)
.setCommit(false)
.setFastForward(MergeCommand.FastForwardMode.FF)
.include(fetchHead)
.call();
} catch (CheckoutConflictException cce) {
List<String> conflicts = cce.getConflictingPaths();
if (conflicts != null && conflicts.size() > 0) {
for (String file : conflicts) {
if (file.endsWith(".json")) {
revert(Paths.get(file));
}
}
}
}
/// ... and now that we've reverted any conflicted JSON files, we can try the merge for real
MergeResult mergeResult = this.repo().merge()
.setStrategy(MergeStrategy.RECURSIVE)
.setCommit(true)
.setFastForward(MergeCommand.FastForwardMode.FF)
.include(fetchHead)
.call();
return mergeResult.getMergeStatus().toString();
}

I was able to get the behavior I wanted using stashCreate() and stashApply(). Specifically, stashCreate() to stash any changes left after reverting any JSON files, then using PullCommand (not MergeCommand) to pull any new changes, then using stashApply() to apply any stashed local changes. I tested it with no conflicts, conflicts in JSON files, conflicts in other files where different parts of the file were changed between local and remote, and other files where the same line(s) were changed. It worked in all of the above cases.

Related

Get file content on Github with GraphQL API and Python

Given a list of repositories on GitHub with 'repoName' and 'userName', I need to find all the '.java' files, and get the content of the java files. Tried to use RestAPI first, but ran into the rate limit very easily, now I'm switching to GraphQL API, but don't know how to achieve that.
Here is how I would do it:
Algo Identify_java_files
Entry: path the folder
Out: java files in the folder
Identify all files in the folder of the repository
For each file
if the type of the file is "blob":
if ".java" is the end of the name of the file
get its content
else if the type of the file is "tree":
Identify_java_files(path of the tree file)
You can easily implement this pseudo code using Python. My pseudo code makes the assumption to use recursion, but it can be done otherwise, it's just for the example. You will need the requests and json libraries.
Here are the queries you might need, and you can use the explorer to test them.
{
repository(name: "checkout", owner: "actions") {
defaultBranchRef {
name
}
}
}
This query allows you to check the name of the default branch of the repository. You will need it for the following queries, or you can use a specific branch but you will have to know its name. I don't know (and don't believe) if you can get all the branches names for a repository.
{
repository(name: "checkout", owner: "actions") {
object(expression: "main:") {
... on Tree {
entries {
path
type
}
}
}
}
}
This query gets the content of the root folder for a specific repository. The expression: "main:" refers to the branch of the repository along with the path. Here the branch is main and the path is empty (it comes after the ":"), meaning we are looking at the root folder. Some repositories are using "master" as default branch, so be sure of which branch to use.
To check the content of a file, you can use this accepted answer.
I updated the example in order for you to be able to try it.
{
repository(name: "checkout", owner: "actions") {
object(expression: "main:.github/workflows/test.yml") {
... on Blob {
text
}
}
}
}
You send your requests to the API using requests or alike, and store the responses as JSON or alike for treatment.
As a side note, I do not think it is possible to achieve this without issuing multiple queries. I recently had to do something similar, and this is my first SO answer, so let me know if anything is unclear.
Edit:
You can use this answer to list all files in a repository.

How to determine if need to git_commit_create() after the merge()?

When I use libgit2 to update data, pull seem to create unnecessary short-term branches and merges which are a headache to resolve. and each merge produced a new oid, so there should be a function to determine if a merge commit is needed before the merge commit. wondering if it is a good practice, then what is the best way to do it?
If you want to analyze whether a merge is needed between two branches, or if instead it is fast-forwardable, use the git_merge_analysis function:
git_merge_analysis_t analysis;
git_merge_preference_t preference;
int error = git_merge_analysis(&analysis, &preference, repo, merge_heads, merge_head_len);
if (analysis == GIT_MERGE_ANALYSIS_FASTFORWARD) {
/* You can simply do a fast-forward */
} else {
/* You need to do a true merge */
}
You may wish to examine the preference to know whether the user has asked to never fast-forward.

how to get a list of commits from refChanges in Atlassian Stash Pre Receive Repository Hook

Im trying to write a stash plugin that will iterate through the commits in a change set pushed to stash in a Pre Receive Repository Hook.
The API passes a Collection of refChange in the onReceive method.
public boolean onReceive(RepositoryHookContext context, Collection<RefChange> refChanges, HookResponse hookResponse)
if I make 3 commits then push I get one RefChange which looks like this
refId = refs/heads/master
fromHash = ded3e4583653f14892cc3e8a898ba74ee75e1a58 // First Commit in change set
toHash = ae017dcdadf7ca69617fb05f6905cccfe2aa4229 // Most recent commit
type = "UPDATE"
Id like to get a collection of all the commits so that I can get all the commit messages.
I'm looking at com.atlassian.stash.commit.CommitService getCommit and getCommits. I think I need to getCommitsBetween but can't quite figure out how to crate the GetCommitsBetween parameter needed from the RefChange I have.
Am I even heading down the right path here?
Even though the CommitsBetweenRequest page on the Atlassian Stash API documentation is one of the few pages with an explanation, it took some trial and error to figure this out. GetCommitsBetween works but here's the trick...
Set the commitsBetweenBuilder.exclude to the starting commit in the change set and commitsBetweenBuilder.include to the ending commit hash.
CommitsBetweenRequest.Builder commitsBetweenBuilder = new CommitsBetweenRequest.Builder(context.getRepository() );
commitsBetweenBuilder.exclude(refChange.getFromHash()); //Starting with
commitsBetweenBuilder.include(refChange.getToHash()); // ending with
PageRequest pageRequest = new PageRequestImpl(0,6);
Page<Commit> commits = commitService.getCommitsBetween(commitsBetweenBuilder.build(), pageRequest);
//TODO: handle Pages
for (Commit commit : commits.getValues()) {
hookResponse.out().println("Message = " + commit.getMessage() + "\n");
}
I wasn't able to get the dependency injection working for the CommitService. Spring for some reason wasn't able to find it, when trying to run in locally ???
I did getting it working using the component locator.
CommitService commitService = ComponentLocator.getComponent(CommitService.class);

Commit a whole folder with modified files in it with SharpSvn.

I am using SharpSvn in my C# project. I am having a folder with some text files in it and another folders with subfolders in it. I am adding the folder under version control and commit it. So far, so good. This is my code:
using (SvnClient client = new SvnClient())
{
SvnCommitArgs ca = new SvnCommitArgs();
SvnStatusArgs sa = new SvnStatusArgs();
sa.Depth = SvnDepth.Empty;
Collection<SvnStatusEventArgs> statuses;
client.GetStatus(pathsConfigurator.FranchisePath, sa, out statuses);
if (statuses.Count == 1)
{
if (!statuses[0].Versioned)
{
client.Add(pathsConfigurator.FranchisePath);
ca.LogMessage = "Added";
client.Commit(pathsConfigurator.FranchisePath, ca);
}
else if (statuses[0].Modified)
{
ca.LogMessage = "Modified";
client.Commit(pathsConfigurator.FranchisePath, ca);
}
}
}
I make some changes to one of the text files and then run the code againg. The modification is not committed. This condition is false:
if (statuses.Count == 1)
and all the logic in the if block does not execute.
I have not written this logic and cannot quite get this lines of code:
client.GetStatus(pathsConfigurator.FranchisePath, sa, out statuses);
if (statuses.Count == 1) {}
I went on the oficial site of the API but couldn`t find documentation about this.
Can someone that is more familiar with this API tell what these two lines do ?
What changes need to be done to this code so if some of the contents of the pathsConfigurator.FranchisePath folder are changed, the whole folder with the changes to be commited. Any suggestions with working example will be greatly appreciated.
Committing one directory with everything inside is pretty easy: Just call commit on that directory.
The default Depth of commit is SvnDepth.Infinity so that would work directly. You can set additional options by providing a SvnCommitArgs object to SvnClient.Commit()

How two people, concurrently editing the same file is handled?

I believe the title says it. I'm new to source control thingy.
So, let's say I have two developers working on the same project and they started editing the same file(s) at the same time then everyone of them send the new version at a slightly different time. From what I understand the one who sends the changes last will have his changes kept, the other one's code will be in the archive only!!!
Is that correct?
Please clarify. Thanks.
No, that's not quite correct. It depends somewhat on which version control software you're using, but I like Git so I'll talk about that.
Suppose we have a file Foo.java:
class Foo {
public void printAWittyMessage() {
// TODO: Be witty
}
}
Alice and Bob both modify the file. Alice does this:
class Foo {
public void printAWittyMessage() {
System.out.println("Alice is the coolest");
}
}
and Bob does this:
class Foo {
public void printAWittyMessage() {
System.out.println("Alice is teh suk");
}
}
Alice checks her version in first. When Bob attempts to check his in, Git will warn him that there is a conflict and won't allow the commit to be pushed into the main repository. Bob has to update his local repository and fix the conflict. He'll get something like this:
class Foo {
public void printAWittyMessage() {
<<<<< HEAD:<some git nonsense>
System.out.println("Alice is the coolest");
=====
System.out.println("Alice is teh suk");
>>>>> blahdeblahdeblah:<some more git nonsense>
}
}
The <<<<<, ===== and >>>>> markers show which lines were changed simultaneously. Bob must resolve the conflict in some sensible way, remove the markers, and commit the result.
So what eventually lives in the repository is:
Original version -> Alice's version -> Bob's conflict-fixed version.
To summarise: the first to commit gets in without any problems, the second to commit must resolve the conflict before getting into the repository. You should never end up with someone's changes being clobbered automatically. Obviously Bob can resolve the conflict incorrectly but the beauty of version control is that you can roll back the incorrect fix and repair it.
Much depends on the system you're using.
However in the common case is: who commits his changes second would have to perform a "merge" operation. Meaning s/he would need to compare the two files and come up with a merged version. However (!) many popular system (including IDE) comes with smart tools to assist you doing that.
Here are some tools like that compared:
http://en.wikipedia.org/wiki/Comparison_of_file_comparison_tools