How to merge with mercurial - macos

I created a repo and made some changes into a file. Then I committed and kept working. A couple of changes and I committed again.
I had to go back to the first version, so I did:
hg up 5f01300
And the files from the first version came back.
I made some changes and committed again.
hg commit -m 'Updated'
A new head was created and then I tried:
hg push
Mercurial said there were "outstanding uncommitted" stuffs.
I tried to commit again:
hg commit -m 'Changes accepted'
Then I typed:
hg merge
So a lot of errors appeared because there were two heads and I couldn't merge them.
Sometimes I try to merge like I did above and it works perfectly. Usually at the second time I try to repeat the process, it breaks and I can't merge anything.
Can somebody teach how to merge properly?
[SOME ERRORS]
Usually, at the second time, this is what happens:
int main(int argc, char **argv)
{
printf("hello, world!\n");
<<<<<<< local
printf("sure am glad I'm not using CVS!\n");
=======
printf("sure am glad I'm using Mercurial!\n");
>>>>>>> other
return 0;
}
And I have to do:
hg resolve -m hello.c

Merging is how you combine divergent versions of your files. Whenever you change a file in two different ways, Mercurial will try to merge it when you run hg merge.
When the changes to the files don't overlap, Mercurial can do the merge automatically. However, if you change the same line in two different ways, then you need to help Mercurial merge the two edits.
Consider a file that starts with hello, world! in the first revision and then changes into sure am glad I'm not using CVS! in the second revision:
"hello, world" --- "sure am glad I'm not using CVS!"
You now update back to the first revision and make a different change to the text:
"hello, world" --- "sure am glad I'm not using CVS!"
\
\
\
"sure am glad I'm using Mercurial!"
You now have a divergent history and when you hg merge, Mercurial will tell you that it has detected a conflict in the file. Mercurial will search for a merge tool and if it cannot find any on your system, it will dump the conflicting changes in the file. The file then looks like this:
<<<<<<< local
sure am glad I'm not using CVS!
=======
sure am glad I'm using Mercurial!
>>>>>>> other
The markers you see are called merge markers and they show you the region of the file that couldn't be automatically merged. The top region marked with local is the version you had in your working copy before you typed hg merge. The bottom region marked other is the version that was on the branch you merged with.
Mercurial knows that the file is unresolved and you can see with with hg resolve --list. You now edit the file to somehow combine the two versions. Here's one combination:
sure am glad I'm using Mercurial and not CVS!
I've deleted the merge markers and left behind a version I like. You now mark the file as resolved and commit the merge:
$ hg resolve --mark hello.c
$ hg commit
I hope that helps!
Another comment: You write
[...] I tried: hg push. Mercurial said there were "outstanding uncommitted" stuffs.
Mercurial never talks about uncommitted changes when you try to push. Pushing and pulling are unrelated to your working copy (where your uncommitted changes live). So it is okay to push and pull with a dirty working copy. The error you're thinking of is probably
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg merge
abort: outstanding uncommitted merges
That is, you cannot start a new merge before you commit or abort the current merge.

Related

How to deal with yarn's `.pnp.js` merge conflicts?

Using yarn 2's new plug n play (pnp) creates a long .pnp.js file. I get a bunch of merge conflicts while pulling, and these are not autofixed (unlike yarn.lock).
How are these conflicts solved? I'd rather not go them through manually as it's not clear what change to accept.
Example conflict
["virtual:844e49f9c8ad85b5809b347eb507fe8bfdc2d527102f53e0b4f78076a2ad5ea2556763170701137a2cafdc51d5a36d82e448010e65742a300748e0bc70028101#npm:11.2.7", {
"packageLocation": "./.yarn/$$virtual/#testing-library-react-virtual-2e67fd5293/0/cache/#testing-library-react-npm-11.2.7-3a0469c756-389c9f3e83.zip/node_modules/#testing-library/react/",
"packageDependencies": [
["#testing-library/react", "virtual:844e49f9c8ad85b5809b347eb507fe8bfdc2d527102f53e0b4f78076a2ad5ea2556763170701137a2cafdc51d5a36d82e448010e65742a300748e0bc70028101#npm:11.2.7"],
["#babel/runtime", "npm:7.13.10"],
<<<<<<< HEAD
["#testing-library/dom", "npm:7.30.4"],
["#types/react", "npm:17.0.3"],
["#types/react-dom", "npm:17.0.3"],
=======
["#testing-library/dom", "npm:7.31.0"],
["#types/react", "npm:17.0.8"],
["#types/react-dom", "npm:17.0.5"],
>>>>>>> d2bb5d9e537f9647e9757656de230e56282e0b15
["react", "npm:17.0.2"],
I would assume you can delete this file containing merge conflicts.
Next, you run yarn install which will generate this file again.
Or just run yarn install which will overwrite the the .pnp.cjs file and fix the merge conflicts (if any) in the yarn.lock file for you.
From the docs:
The generated .pnp.cjs file can be committed to your repository
as part of the Zero-Installs effort, removing the need to run yarn install in the first place.
As you can read, this file can - not must - be committed. However, if you commit it, you can use all your dependencies immediately after cloning the repo, switching branches, ... without need to run yarn install every time.
Note that the same does not count for yarn.lock file which you should never delete.

Generating release notes from git commits

I've created the following rake task below to generate our release notes for each sprint.
I'm pulling in all commits to master older than 2 weeks.
The problem is when a branch has been developed on for more than 2-week sprints, the older commits won't be included.
Can anyone suggest a way I can get these commits in?
task :new_release_note do
puts "Creating new release note"
puts "..."
git_log = `git log --since="two weeks ago" --no-merges --format=%B`
git_log.gsub!(/^$\n/, '')
git_log.gsub!(/^/, "* ")
current_time = DateTime.now
current_date = current_time.strftime "%Y-%m-%d"
current_date_UK = current_time.strftime "%d-%m-%Y"
template = "__Release Notes__
=======================
#{current_date_UK}
__New Features__
----------------
* -
__Improvements__
----------------
* -
__Fixes__
---------
* -
__Change Log__
----------------
Detailed release notes below, listing all commit messages for this release.
#{git_log}
"
out_file = File.new("./doc/release_notes/release-notes-#{current_date}.md", "w")
out_file.puts(template)
if File.exist?(out_file)
puts "New release note generated successfully at /doc/release-notes/release-notes-#{current_date}.md"
else
puts "Error - file not generated."
end
end
Can anyone suggest a way I can get these commits in?
Few options:
git tag
git notes
git whatchanged
git tag
Read this answer on what is git tag and how to use it: What is git tag, How to create tags & How to checkout git remote tag(s)
In short: git tag allows you to mark commit which can be later on to perform your merge. As you know
git pull = git fetch + git merge
So once you have marked your last merge with the tag you can pull out all the changes form the last merge
# "Merge" the last X commits based upon your previous tag
git cherry-pick <tag_name>..master
git notes
git notes allow us to add content to commit without updating the SHA-1 of the commit, meaning we can attach content to the commit while leaving the SHA-1 unmodified.
Now once you have your notes you can find out the last commit which you "merged" previously and grab the changes from this point on using the above cherry-pick.
You can search and find your notes with git log --grep
git whatchanged
Once you what is your referenced commit you can see the list of files which were updated during this time period with the git whatchanged command
# Print out a list of files which was updated/added between the 2 commits
git whatchanged <TAG_NAME>...HEAD
Consider using git tag and tag your releases with version numbers. What my team does is to create a release branch with a version number for each release i.e. release-2.5.8 and when the release is ready, it gets merged into master. Then we tag that merge commit with a version number i.e. v2.5.8 If you do this, along with squash merges then to see all the related commits it's as easy as doing:
git log v2.5.8...v2.5.9
Which will show you all the commits within those 2 releases.
The reason I recommend squash merging your feature branch is for exactly your use case. You want to know what was done during the dev of that feature, but how can you just by date? You really can't. So when your feature is ready to be merged into your release, if you squash merge, you can keep all the notes in a single commit for the merge of that feature. The idea here is you keep what is relevant and discard what is no longer needed during development.
You might also want to check out Gitflow

Terminal ANSI escape codes don't work

When I was using Arcanist and landing some code I found out that my terminal does not escape the colors. The <ESC>[1;32m9912da1<ESC>[m is supposed 32m9912da1 or something similar. Is this a problem with my terminal? Other people at my work don't find this problem.
Landing current branch 'some-branch'.
TARGET Landing onto "master", selected by following tracking branches upstream to the closest remote.
REMOTE Using remote "origin", selected by following tracking branches upstream to the closest remote.
FETCH Fetching origin/master...
These commits will be landed:
- <ESC>[1;32m9912da1<ESC>[m some commit
- <ESC>[1;32m687f799<ESC>[m some other commit
If you are using arcanist on windows with git bash this should fix it:
# add the following function to your .bash_profile
function arc(){
command arc --ansi $#|cat
}
For detailed instructions see: https://thomas-barthelemy.github.io/2015/04/23/phabricator-arcanist-gitbash/

Merging two branches in Rugged

Using Rugged, I create a new branch from master (let's call it new_branch), modify a file and create a commit for that. Now I want to merge this branch into master, push master to remote and delete new_branch.
At the point of running the code below there are no modified files and no staged files on either branch as the modified is committed into new_branch.
This is the code I use:
from_branch = #repo.head.name
their_commit = #repo.branches[into_branch].target_id
our_commit = #repo.branches[from_branch].target_id
index = #repo.merge_commits(our_commit, their_commit)
if index.conflicts?
# conflicts. deal with them
else
# no conflicts
commit_tree = index.write_tree(#repo)
#repo.checkout(into_branch)
commit_author = { email: GIT_EMAIL, name: GIT_NAME, time: Time.now }
Rugged::Commit.create(#repo,
committer: commit_author,
message: "Merge #{from_branch} into #{into_branch}",
parents: [#repo.head.target, our_commit],
tree: commit_tree,
update_ref: #repo.branches[into_branch].canonical_name)
#repo.push('origin', [#repo.head.name], { credentials: #cred })
#repo.branches.delete(from_branch)
end
This works as expected (modified file is merged into master, it is pushed to remote and the new branch is delete), however once it's done, I am left with the modified file showing under master as modified and staged, ready to be committed while there shouldn't be any modified files in the working directory and nothing staged. Everything should be up-to-date.
In your code you are updating an arbitrary branch, so the index and worktree should not be of concern in the general case.
If you are merging into the current branch, then (and only then) you are missing the steps to update both the index and the worktree with the results of the merge. You can use
#repo.checkout_tree(commit_tree)
to checkout the files as they are on the resulting commit. This will also update the repository's index file to have the contents of that tree. You can then update the current branch to point to the merge commit.
You have a call to #repo.checkout(into_branch) but since you already seem to be in into_branch in your case, that will at best do nothing. You need to checkout the result of the merge, the branch, index or workdir are not touched by the #repo.merge_commits() call.

Update Local Workspace to SVN Repository 'Head' With Ruby SVN Bindings

I am writing a program in Ruby that necessitates downloading the most current version of my team's software from SVN upon start up.
The checkout function (from the Ruby SVN bindings) is what I believe I want to use, because an update would not ADD any files that do not exist on my machine's local "trunk" workspace. A checkout statement would both update files that do not match to HEAD, and it would download ones that don't exist at all. Effectively, after running a fully recursive checkout, I would hope to have an exact copy of the most recent SVN repository.
According to this API, a checkout statement basically takes the following:
an exact SVN URL
a local root project directory
a revision (I would be using the string 'HEAD')
recursive (integer 1 or 0)
a pool object (I cannot determine what this is for exactly, but I don't think it affects me)
Here's what I wrote, inside a block that iterates for each file in the SVN repository:
if status != NORMAL #any file that changed or is 'missing'
ctx.checkout(status.entry.url, ROOTDIR, 'HEAD', 0, nil) #update abnormal file to HEAD
end
As a test, I erased a directory from my local workspace, and attempted to restore it with this command. It runs through until it reaches one of the missing files, at which point it raises an error:
`svn_client_checkout3': subversion/libsvn_fs_fs/tree.c:663: Svn::Error::FsNotFound: File not found: revision 0, path '/trunk/project-gadfly/SocketServer/DiscoveryServer.cpp' (Svn::Error::FsNotFound)
I do not understand why this error would be raised, because I thought that a checkout statement would see that the directory (i.e. file) does not exist locally and then create it. Perhaps I am doing something wrong?
Looking back on what I've written, I think all of this was a long-winded way of asking the following simple question: How do I get the most current version of SVN repository onto my local hard drive with an SVN Ruby command?
Thanks in advance,
Elwood Hopkins
I don't know about Ruby-specific part of the question, but it's clear that you asked SVN API to checkout "status.entry.url" at revision 0, which of course doesn't exist here.
It's also strange that you looked into Perl documentation for writing in Ruby. I would recommend you to look at Subversion sources instead.
Here's Ruby method declaration:
http://svn.apache.org/repos/asf/subversion/branches/1.7.x/subversion/bindings/swig/ruby/svn/client.rb
def checkout(url, path, revision=nil, peg_rev=nil,
depth=nil, ignore_externals=false,
allow_unver_obstruction=false)
revision ||= "HEAD"
Client.checkout3(url, path, peg_rev, revision, depth,
ignore_externals, allow_unver_obstruction,
self)
end
So as you can see, you've specified 0 as peg revision. But you should specify HEAD instead.
What about pools --- they are parts of SVN memory managements. Here's the explanation: http://subversion.apache.org/docs/community-guide/conventions.html#apr-pools

Resources