Use case for private changes - version-control

Supposing I have following scenario: I cloned some open-source project, say from URL X. Now I have local clone of it. I made some changes to local clone to try things out and commited them locally. Now what I want is following:
I want to get update from the open-source project X. Just get all its latest code, without my changes at all. But I want my changes to live somewhere in tag in history so I can get them later. And I don't want to separate clone for this, want it all in my one repo.
For now I did following:
Tag my changes with hg tag
Pull & merge latest code from URL X
Revert repository to latest revision of URL X
But I feel this isn't good way and it's roundabout. I think there's better way. Could you please suggest?

Instead of tags, I would use a bookmark. If you use Mercurial 1.8 or later, you already have the bookmark functionality built-in. Otherwise, you first have enable the extension by putting the following in your ~/.hgrc file:
[extensions]
bookmarks =
[bookmarks]
track.current = True
Now get the clone of your project:
hg clone http://bitbucket.org/user/X
cd X
and hack away:
# edit, edit, edit...
hg commit -m 'Great new feature!'
Now put a bookmark on this changeset
hg bookmark mywork
This is like a tag, but the advantage of a bookmark is that is moves along when you make new commits. This is just like when you're reading a book and move the bookmark along with you. When the bookmark is created, you can do
hg update mywork
to get back to the bookmarked changeset.
When there has been changes made in the upstream repository, then you pull and merge them into your own branch:
hg update mywork # if necessary
hg pull
hg merge
hg commit -m 'Merged new upstream changes.'
The bookmark will have moved forward and is now pointing to the merge changeset you just created. If you want to update to the version in X, then
hg update --rev -2
will do it after you pulled in changes -- this updates to the old tip changeset from before the merge, which was the tip of X.

Related

Create a hg bookmark after committing a changeset

I cloned a Mercurial repo and made some changes in the checked out code. I then grabbed those changes (7 files) and committed them with hg commit but without having created a bookmark first.
This is the output of my hg summary command:
parent: 8172:b39efc1322fe tip
Made some changes in my feature
branch: default
commit: 7 modified
update: 2 new changesets, 3 branch heads (merge)
phases: 3 draft
These changes won't be ready to be pushed for at least another week, so I want to switch to a new bookmark and work on other parts of the code.
The problem is that I realized that I had made a commit without being in a bookmark, so I'm afraid that after switching to a new bookmark my committed changes could be lost.
Is there an easy way to move these committed changes into a new bookmark?
There is no need to be afraid at all: mercurial won't forget anything you committed unless you explicitly do both: enable history editing extensions and willingly use them in a way that you actually remove one or more changesets.
Mercurial is not git and mercurial does never forget or garbage-collect a changeset when it is not currently checked out and has no name (bookmark) attached to it.
You can show you all your heads using hg heads. And you can always create new bookmarks, attached to an arbitrary changeset by hg bookmark --rev XXX MyBookmark where XXX is the changesetID to which you want to attach the bookmark.
I'm afraid that after switching to a new bookmark my committed changes could be lost.
How can you imagine this? OMFG, you committed your changes to repository (your clone), you have this changeset (8172:b39efc1322fe) in it. When|if you'll svn up to another node, you'll just change parent of your Working Directory, on pull you'll get "2 new changeset" and, as result "3 branch heads" - 2 new changesets + your commit 8172, and this b39efc1322fe will be always one of heads, even you'll up and work in another.
If you are afraid to forget it (how??? really), you can post-fact bookmark this (committed) changeset with hg bookmark -r b39efc1322fe $WIP && hg commit -m "Bookmarked my work" in order to hg up $WIP when it will be time to continue this chunk of changes

git push to remote and lose all history

I have a git project that I'm about to push to SourceForge. The origin for my local repo is a shared file system repo that gives me a backup facility.
When I eventually add SF as another remote I just want to push the latest (= versioned) commit to it as the starting base of my code on that repo, and not include all the previous commits that contain possibly rubbish/sensitive/embarrassing code.
My question is similar to this one, except that question was about just leaving out some of the history - I want to leave out all of the history and have the latest commit to become the starting point of the project code on SF. Importantly, having done this, I want "push to upstream" to continue to work even though origin and SF will be different.
Is this possible? Incidentally I'm doing this through Eclipse ie. eGit.
Update
My original question should have been clearer, although the answers so far have helped clarify exactly what I'm trying to achieve.
I want just consolidated commits pushed to SF, representing the published versions.
This is what I want to do:
[master] A--B--C--D--E--F--G--H--I... --> push to origin (private)
\ \
[public] V1----------V2... --> push to public remote repo
#michas's answer starts me off with V1 on branch public, but I can't figure out how to continue to extend this branch with subsequent version commits. I've experimented with rebase but can't get the result I want.
It sounds like you want to start with a new repo. Why don't you just delete or rename your old repo and create a brand new one. Then copy all of your files in, commit them, and push.
Well, you cannot push the current commit, as this commit contains the whole "rubbish" history.
However you can create a new commit with the same content but without any history.
git checkout --orphan fresh # create a new branch called `fresh` without any history
git commit # add your work as a new commit
git diff fresh master # the both branches should contain the same content (assuming you original branch was called `master`)
git log # verify the current branch does not contain any history
git push sf fresh # push that branch
git push sf fresh:master # (or you might want to call that branch master on sf)
The answer provided by #michas didn't allow me to subsequently maintain the branch with consolidated history. This required the use of git merge --squash. The scheme I eventually came up with was similar to the one described here.
Just tidying up so the question has an upvoted answer.

Reverting to last commit in Xcode 4 using Git

We just moved over to Git from SVN. In trying to clean up some unused files. I saved before deleting one folder that I thought we weren't using. I did not push this to the origin. I realized we are using one of the files in the folder after all, and would like to revert to my last commit. This is on my own branch from the master. I can't find a way to do that in Xcode. Am I missing something? Thanks.
You can see here for rsanchezsaez answer: Xcode 4 git integration
Xcode 4 won't let you to checkout older commits within the user interface, unless you created a new branch for that commit. Nevertheless, you can do it from the command line. For that, use the following command from your project folder
$ git log --format=oneline
to get the hash code of the commit you want to go to, and then use:
$ git checkout desired-hash-code
to checkout that particular version. Once there, you can make tests, changes, and possibly create a new branch. If you do a commit without creating a new branch, you will lose the newer commits in your current branch. If you want to go back to the newest commit after having performed some tests on your older version use:
$ git checkout master
note again that this won't work if you do a new commit from your old code version without creating a new branch, because newer commits in the current branch get dereferenced.
Also, please consider searching SO before asking. Many questions had already been asked and answered.
From the command line, run a program called gitk - this will allow you to visualize the commits you currently have. Find the ID of the commit you want (e.g. the previous commit) and do the following on your branch:
git tag JustInCase
git reset --hard <commit ID>
Refresh gitk, and if you're happy with the results then delete the tag using:
git tag -d JustInCase
If you're not happy with it, just do:
git reset --hard JustInCase
git tag -d JustInCase
To visualize this for you:
1) Start
2) After tagging and resetting your branch to the previous commit.
3) After deleting the tag and doing Reload in gitk.

How can I restore files before a certain commit in GitHub?

How can I restore files before a certain commit in GitHub?
If you want to retrieve an individual file from before the commit f4l4fe1, for example, you can do:
git checkout f4l4fe1^ -- some/file.txt
(When you add a ^ to a ref in git, it means the parent of that commit.) You should find some/file.txt back in your working tree, but note that it will also be staged as a change to commit.
If you want to just see the working tree as it was on the previous commit, you can check out the commit as if it were a branch:
git checkout f4l4fe1^
That puts you into a state known as "detached HEAD" where you're no longer on a particular branch, so making new commits won't advance any branch. To get back to master, say, you'd just do git checkout master.
As a third option, suppose you want to extract a whole directory from that commit, or a whole subdirectory, you can use git archive and pipe the output to tar, as explained in: What's the best way to extract a tree from a git repository?

Delete all local changesets and revert to tree

I'm using Mercurial and I've got into a terrible mess locally, with three heads. I can't push, and I just want to delete all my local changes and commits and start again with totally clean code and a clean history.
In other words, I want to end up with (a) exactly the same code locally as exists in the tip of the remote branch and (b) no history of any local commits.
I know hg update -C overwrites any local changes. But how do I delete any local commits?
To be clear, I have no interest in preserving any of the work I've done locally. I just want the simplest way to revert back to a totally clean local checkout.
When the simplest way (a new hg clone) isn't practical, I use hg strip:
% hg outgoing -l 1
% hg strip $rev # replace $rev with the revision number from outgoing
Repeat until hg outgoing stays quiet. Note that hg strip $rev obliterates $rev and all its descendants.
Note that you may have to first enable strip in your Mercurial settings.
PS: an even smarter approach is to use the revset language, and do:
% hg strip 'roots(outgoing())'
You'll want to make a local clone where you preserve only the changesets that are also present in the remote repository. Use TortoiseHg, hg log or similar to figure out which of your revisions is that lastest revision you didn't make (the one before the mess started). Using hg outgoing can help here -- it will list all the changesets you made -- pick a revision number earlier than any of those.
If the target revision is called good and your clone is called foo, then do:
hg clone -r good foo foo-clean
This will be a fast, local operation -- there is no reason to download everything again. The foo-clean clone will only contain changesets up to revision good. You can now replace foo-clean/.hg/hgrc with foo/.hg/hgrc in order to preserve your repository-local settings such as the default push/pull path.
When you are satisfied that foo-clean has everything you need from foo, then simply delete foo and rename foo-clean to foo. Do a hg pull to get any new changesets from the remote repository into your clone and continue like normal.
If nobody has pushed new changesets to the remote repository, then it is very simple to determine which revision you want to use as good above: hg id default will tell you the ID of the tip in the remote repository.
Ok. So just delete all the local stuff, hg init the new local repository and hg pull the latest tip you have. Don't forget to hg update after this.
You may use
hg strip revision
to kill any revision and its subtree in your local repository.
https://www.mercurial-scm.org/wiki/Strip
But don't try to use it for anything that has been already pushed.
Just delete everything you have on your local system and re-clone the remote repo.
hg strip `hg out --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`
does the trick for me.
It strips all revisions that aren't pushed to the default repository which are created with your author name.
You can also use this style to make it not checking with the default repository but with another Repository
hg strip `hg out OTHER_REPO_ALIAS --template "{rev} {author}\n" | grep YOUR_AUTHOR_NAME | cut -d " " -f 1`
If you are using TortoiseHg, one simple way to get out of a (small) mess is to first update to the latest revision, then select your changesets and initiate "merge with local". When the merge dialogue appears, simply click the little '+' icon to reveal some extra options, one of which is "discard changesets from merge target (other) revision". Doing this will mean your changesets will still be in the repo and get pushed, but will have no effect, because they will be discarded in the merge. If you have a lot of changesets spanning many heads, you might not want to pollute the repo this way, but it's a simple fix and worth considering if the changesets you are discarding contain data that you may later want to reference.