hg-git: `unknown revision` with one git clone, ok with another - hg-git

Closed: I started a hg clone... by error in the git repository and this created an empty hg repository. So hggit checks the differences with the empty hg repo and not the git conversion.
$ hg incoming -r branchname_bkm G1
comparing with /home/xxxx/src
abort: unknown revision 'branchname_bkm'
_bkm is the suffix I use between git branches and hg bookmarks.
I have a mercurial repository for long time (named HG0).
I converted it to git using the hggit extension, pushed it to gitlab.
I usually develop in the git repo (named G1) but our official repo is still mercurial.
When needed, I import a git branch (as bookmarks) this way:
update the hg-git map:
cd HG0
hg pull
hg update main_bkm # bookmark on default == main
hg git-cleanup
hg outgoing G1
import git branch:
hg in -r <branchname> G1
It worked perfectly during months.
For about 2 weeks, hg out shows me all the changesets, not only the new ones and hg in returns unknown revision!
I created a new git clone G2 from gitlab. hg out G2 is correct and only shows few revs as expected.
I could exchange my git branch from G1 to G2 and get it in HG0, ok.
How can I "re-synchronize" my hg repo with G1?
git-cleanup does not change anything.
I even tried to entirely rebuild the embedded .hg/git (~2 hours), no change.
If I grep a revision shown by hg out G1 in .hg/git-mapfile, it corresponds to the related revision in G1...
May git garbage collection process "hides" something used to identify the repo?
Thanks in advance.

Related

Add a parent to the original changeset in Mercurial

I have a project with 24 months of source control history in a Mercurial repository.
I've recently found some old tarballs of the project that predate source control, and i think they would be useful to import into the repository as "pre-historic" changesets.
Can i somehow add a parent to my initial commit?
Alternatively, is it possible to re-play my entire repository history on top of the tarballs, preserving all metadata (timestamps etc)?
Is it possible to have the new parent commits use the timestamps of these old tarballs?
You can use the convert extension to build a new repository where the tarballs are imported as revisions before your current root revision.
First, you import the tarballs based on the null revision:
$ hg update null
$ tar -xvzf backup-2010.tar.gz
$ hg addremove
$ hg commit -m 'Version from 2010'
$ rm -r *
$ tar -xvzf backup-2011.tar.gz
$ hg addremove
$ hg commit -m 'Version from 2011'
I'm using addremove above to give Mercurial a chance to detect renames between each tarball (look at the --similarity flag to fine-tune this and use hg rename --after by hand to help Mercurial further). Also, I remove all the files in the working copy before importing a new tarball: that way the next commit will contain exactly the snapshot present in the tarball you unpack.
After you've imported all the tarballs like above, you have a parallel history in your repository:
[c1] --- [c2] --- [c3] ... [cN]
[t1] --- [t2] --- [tM]
Your old commits are c1 to cN and the commits from the tarballs are t1 to tM. At the moment they share no history — it's as if you used hg pull -f to pull an unrelated repository into the current one.
The convert extension can now be used to do a Mercurial to Mercurial conversion where you rewrite the parent revision of c1 to be tM. Use the --splicemap flag for this. It needs a file with
<full changeset hash for c1> <full changeset hash for tM>
Use hg log --template '{node} ' -r c1 -r tM > splicemap to generate such a file. Then run
$ hg convert --splicemap splicemap . spliced
to generate a new repository spliced with the combined history. The repository is new, so you need to get everybody to re-clone it.
This technique is similar to using hg rebase as suggested by Kindread. The difference is that convert wont try to merge anything: it simply rewrites the parent pointer in c1 to be tM. Since there is no merging involved, this cannot fails with weird merge conflicts.
You should look at using rebase. This can allow you to make the changes the 2nd changeset on your repo ( you have to rebase from the 1st ).
https://www.mercurial-scm.org/wiki/RebaseExtension
However, note that if there are other clones of this repo existing ( such as for fellow developers, or on a repo server ), you will have issues with them pulling the revised repo. You will probably have to co-ordinate with the owners of those clone's to get all work into a single clone, rebase that clone, and then have everyone re-clone from the revised clone. You will also have to change the phase the of the changesets.
https://www.mercurial-scm.org/wiki/Phases
Honestly though, I would just add them to your 'modern-day' repo, I don't think making them pre-historic would give you any notable advantage over adding them to the top.

Diff after committing locally

I just cloned a repo from their remote.
I built the software, changed about 4 files, committed them locally and now want to create a patch that I can show them.
When I run :
hg diff -U8p abc efg pqr > patch_file
I don't see the changes I made. Does hg diff only compare the current files with the last committed files?
How do I get this to work?
To diff the working directory against a particular revision REV, use
hg diff -r REV
To compare two revisions against each other, use
hg diff -r REV1 -r REV2
To figure out which revisions to compare, examine the output of hg log. If you'll be doing this a lot and the base revision is fixed, give it a name (e.g., whatipulled) with
hg tag -r REV whatipulled
You can then specify whatipulled as the revision, instead of a numeric rev id (or a hash).
To export your diffs in a richer format, including commit comments etc., you can also use the following which is designed for this purpose:
hg export -r REV
There's also hg bundle -r REV, which produces a binary file with similar information.
But if you're sending changes back to the parent repo, the best method is to use hg push. It communicates your changesets directly to the parent; you don't even need to know which changesets need pushing. Of course, you must have the right to push to the parent repo.
hg push [ parent_repo_url ]
(If you pulled from it, mercurial should already know the path and you can leave it out).
If the parent repo is on bitbucket and you don't have pu, you can set up your own account on bitbucket, pull/push to that from your local repo, and then issue a "pull request" to the project repo, asking them to pull from you.
All of the above have options to control their behavior, which see.
From hg help diff
If only one revision is specified then that revision is compared to the working directory
In your diff for -r you must to use old tip (latest "not your" changeset) and update to tip (your latest changeset) before diffing.
If some binary data was modified in your changesets, don't forget to use -g option
hg up & hg diff -r <CSET> -g > some.patch
Improved diff for any active changeset and without hand-work for detecting base changeset (for linear history == in single branch)
hg diff -r "parent(min(outgoing()))" -r tip
By default, hg diff compares the currently checked out file with the last commit. You can change this by adding options:
-r REV compares the currently checked out files with a specific revision REV.
-c REV shows the changes made by revision REV
So in your case hg diff -c 123 ... would give you the diff for commit 123.
My guess is that hg outgoing is exactly what you want -- it compares what you've committed locally with what is at the default remote server and shows you a list of those changesets or with -p the commits.
That does, however, shows each changeset separately. If you want to see all the changes combined, you'd have to do hg diff -r HERE -r THERE or since -r HERE is a default, hg diff -r THERE
I see you've asked in a comment "How do I know what THERE is", where THERE is the last changeset remote has, and you can get that answer by doing hg outgoing. If hg outgoing shows it would send changesets 66, 67, and 68, then you want to do hg diff -r 65 to compare what's already there (65) with what's local (68).

mercurial push certain revision

I have searched here, but haven't found any question related to this. I got a problem like this in mercurial:
I manage open source project in bitbucket, so i have clone of the source code in my local. But I also using that project for my own live site, so I made 2 clone of bitbucket repo
Bitbucket Repo
|
==local_clone1
|
==local_clone2-> commit1 => commit2 => commit3
(personalization) (bug fix) (add feature)
The question is, I want to push commit2 and commit3 back to local_clone1, so later on I can push to Bitbucket repo. But don't want to push commit1, since it has my personal data.
Wondering how we do that in mercurial?
This can be done without too much difficulty in this case. See Removing history in the Mercurial guide for more information.
Here's the basics of what you'll need to do:
Go to local_clone2
Get the revision number (hg tip will show you) from the current number. We'll call it 731.
hg export 730-731 > ../local_clone1/changes.diff (or wherever you like)
Go to local_clone1
hg import changes.diff
You may need to edit things manually; refer to that guide for more info in that case.
Here are a couple of options:
backout
Given a history constructed as:
hg init db
cd db
echo >file1
hg ci -Am clone # rev 0
echo >file2
hg ci -Am personalization # rev 1
echo >file3
hg ci -Am bugfix # rev 2
echo >file4
hg ci -Am feature # rev 3 <tip>
Then if the current working directory is the tip, the following commands will "undo" the personalization revision:
hg backout 1
hg ci -m backout
The advantage is history remains immutable, but shows the addition and backout of the personalization changeset.
Mercurial Queues
With the mq extension, history can be edited to remove a changeset:
hg qimport -r 1:3 # convert changesets 1-3 to patches
hg qpop -a # remove all patches (can't delete an applied patch)
hg qdel 1.diff # delete rev 1's patch
hg qpush -a # reapply remaining patches
hg qfin -a # convert all applied patches back to changesets.
The advantage is the personalization changeset disappears. The disadvantage is the changeset hashes change due to the history edit, so this should never be done to changesets that have already been pushed to others. There is also the risk of a mistake editing history.

How to apply a collapsed revisions patch to trunk in Mercurial?

I am looking for best practices to do the following:
When I need to implement a feature or fix a bug, I am creating new Mercurial repository from the main one (a trunk).
Then, within some days, or weeks, I am implementing the task in newly created repository, making commits and periodically merging with trunk. After the code in new repository will pass all code reviews, I should provide a repository with all changes collapsed into single revision.
My common way to do this (rdiff extension should be enabled):
hg clone ~/repos/trunk ~/repos/new-collapsed
cd ~/repos/new-collapsed
hg diff ~/repos/new > new.diff
patch -p1 < new.diff
hg commit
This works almost well except when there are binary files present in the changes from ~/repos/new. Another way could be:
hg clone ~/repos/trunk ~/repos/new-collapsed
cd ~/repos/new-collapsed
hg pull ~/repos/new
hg update
hg rollback
then resolve possible conflicts and manually commit the changes
Both ways look for me somewhat ugly and non-native, so I am looking how this operation could be simplified. I've played with rebase extension, but seems its hg rebase --collapse command does not work with workflow described above.
Any ideas are welcome.
Sounds like a good case for mercurial queues.
I do something similar with the histedit extension.
My workflow is something like:
clone a central repo
commit incremental changes to local repo
clone my local repo to make collapsed repo
hg histedit and select/discard/fold the revisions as needed
hg push the collapsed repo to central repo
pull central repo to local or refresh local from scratch
I ensure that my local repo never gets pushed to the central repo by adding an invalid default-push path to the .hg/hgrc file in the local repo root directory.
Solved: Just add
[diff]
git = True
to your hgrc file, and then use my first solution with rdiff extension, replacing patch with hg import:
hg clone ~/repos/trunk ~/repos/new-collapsed
cd ~/repos/new-collapsed
hg diff ~/repos/new > new.diff
hg import new.diff
hg commit

Mercurial: Convert clones to branches

I am trying to clean up some cloned repositories I have, basically converting clones into named branches.
What's the easiest way to do this?
The only way you can make them named branches would be to rewrite their history, because the name of the branch is part of the history. However, if you can survive without having the branches be named in the past (the future is fine) then you can just pull all the repos into the main one (without merging!) and then label your branches once they're in.
For example, if you have MainRepo, Feature1Repo, and Feature2Repo, you would do the following:
$ cd MainRepo
$ hg pull ../Feature1Repo
$ hg pull ../Feature2Repo
Now, if you look at the DAG in something like TortoiseHg, you'll see a couple different heads. From here, you just hg up and hg branch:
$ hg up feature1headrev
$ hg branch Feature1
$ hg up feature2headrev
$ hg branch Feature2
From here forward, you'll have your named branches.
Note: If the hg pull complains about the repositories not being related, you can do an hg pull -f, which will create multiple tails in the repository. This is usually not how true branches are, but it is sometimes useful.
You could use hg export to create a bundle of changes, and then hg import them to your new branches.
Let's say you have a common base, revA, and then two clones which each diverge from revA into revB and revC.
In the first clone: hg export -r revA -r revB > revB.patch
In the second clone: hg export -r revA -r revC > revC.patch
Now you have two patches containing all the changes made in the clones.
In the original repository:
hg up revA
hg branch branchB
hg commit
hg import revB.patch
hg up revA
hg branch branchC
hg commit
hg import revC.patch
And now you've got two named branches diverging from revA. If you have merges in the areas between revA->revB or revA->revC, I'm not sure this will preserve them perfectly.
Another alternative is to use the transplant extension. Or you could just push your clones' changes into one repo, and then move the heads that creates to new branches.