Creating a local transparent cache of a mercurial repository - caching

I have lots of different clones which I work on separately. When I want to update those clones, it can be quite slow to update them from the server. So instead I have a "clean" clone, which I update from the server regularly, and all the other clones clone from the clean clone (hope that makes sense).
But now what I have is a two-step approach. First go to the clean clone and pull, and then go to the real clone i'm working on and pull from the clean clone. Can this be made into 1 step?
Ideally, the "clean" clone would be transparent: when it's pulled from, it would do a pull itself. That way we'd have caching and 1-step. Is there a way to do this?

Keeping a clean clone locally is very common and a good idea in general. I've always stuck with the two step process you describe, but you could do this with hooks if you wanted.
In your cache repos you'd put soemthing like this in the .hg/hgrc file:
[hooks]
preoutgoing = hg pull
which tells that repo to do a hg pull before it bundles up changes in response to a pull or clone request made on it.
Note that even if the downstream (real clone) repo requests a subset of the changesets using pull -r or clone -r this cache repo will pull down everything. That's likely what you want since your goal is a mirror but the commenter points it's worth pointing out.

You can do this using hooks. In your <clean-clone>/.hg/hgrc, add these as a first draft:
[hooks]
# Before a pull from this repository, pull from upstream.
preoutgoing.autopull = [ $HG_SOURCE = 'pull' ] && hg pull
# After a push to this repository, push to upstream.
changegroup.autopush = [ $HG_SOURCE = 'push' ] && hg push
(Note: "autopush" and "autopull" are optional identifiers with no special meaning; you can leave them out if you have no other hooks defined.)

Related

Push current code to existing GitHub repository

I have several Visual Studio solutions that have both a local repository and one on GitHub. I've already made many changes and successfully pushed those changes to GitHub.
But now Visual Studio has forgotten that one of my local repositories is associated with a GitHub repository and I can't seem to figure out how to reconnect it. In fact, it no longer lists that repository in my list of GitHub repositories.
In the image below, you can see I have a local repository called Toxic, but that repository does not appear in the list of GitHub repositories. If I try publishing the Toxic project to GitHub, it just tells me the repository already exists.
How the heck can I get all of my existing Github repositories to show up in the top section shown above so I can push my latest changes?
it appears the only option is to clone the GitHub repository locally, copy my modified files over the newly created repository, and then check in my changes.
Try fist:
installing Git for Windows (command-line)
cloning your remote repo in a new folder
adding your existing repository as a remote
fetching and see if you can cherry-pick your commits
That is:
git clone https://github.com/<user>/<repo> newFolder
cd newFolder
git remote add old ../path/to/old/local/repo
git fetch old
git log old/master
git cherry-pick old-sha1..old/master
(with old-sha1 being the first commit you want back)
Then add the newFolder in your Visual Studio workspace, and see if everything works (do a modification, add, commit and push)
Unless I'm missing something, it appears the only option is to clone the GitHub repository locally, copy my modified files over the newly created repository, and then check in my changes.
Of course, I lose all my comments and iterations since the last check in to GitHub. And care had to be taken not to delete the .git folder, and to copy over all changed file and delete any that had been removed. Seems like there should be an easier way but this certainly did the trick.
I'm no git expert, but I think I might be able to help, if I'm not too late.
Run:
git remote -v
This should print something in the form of:
origin <remote_repo_url> (fetch)
origin <remote_repo_url> (push)
If you only see:
origin (fetch)
origin (push)
try running:
git remote set-url origin <remote_repo_url>
If you get no output then run:
git remote add origin <remote_repo_url>
And then try
git push -u origin
The -u or --set-upstream flag will set origin as the default repo for your branches.

How to recover files in git repository

I had a project connected to a local git repository. I decided to reinit that after some mess with branches and commits. Firstly, I deleted old repository with "rm -r .git", and than created new one with "git init". After that, I found out my work directory looking the same way as if my project was only created - the results of all my work are gone.
Trying many recipes from the internet didn't give results. Please, give me a cue, is there any chance to recover my project's files or not.
In the case your "local repository" means you did git clone /path/to/your/local/repo, yes you can restore it by cloning again with git ckibe /path/to/your/local/repo, or git remote add origin /path/to/your/local/repo && git fetch && git pull origin/master ).
Same thing if you cloned from a remote repository.
Otherwise, there is no way to recover your files with git, except if you removed by a graphical interface (which move to a trash folder instead of making a real deletion) or if you have a back up.

git - only fetch the files, not the history

when I am running git pull or git fetch, I obviously retrieve both history and files. For huge projects, that takes very much time. I wonder how this process could be sped up, as for some projects I am only interested in the source code and not in the history. Is there a way to tell git that I only want to fetch the current snapshot of the files and not the whole history as well?
You probably want to look at the --depth option in git clone--called a "shallow clone". In particular, you probably want:
git clone --depth=1 <url>
If the project is on GitHub, you can always use the download links from there. Note, there are some catches to using a shallow clone:
Create a shallow clone with a history truncated to the specified number of revisions. A shallow repository has a number of limitations (you cannot clone or fetch from it, nor push from nor into it), but is adequate if you are only interested in the recent history of a large project with a long history, and would want to send in fixes as patches.
But that sounds like something you can live with.
Also, as positron pointed out, you can do this with git archive as well.
You can use a shallow clone:
git clone --depth=1 git://url/of/repo
However you won't be able to commit/push changes made in a shallow clone.
If there is a webview like gitweb or cgit, you can very well take a snapshot. But I don't think fetch of the code alone is possible. Because fetch is working on your git objects and not the code.
git archive --format=tar --remote=gitolite#server:repo.git HEAD | bzip2 > repo-snapshot.tar.bz2

Working with multiple Git

I have following dir stucture
root
root/framework (Yii)
root/protected/messages
All of this folder must be separate git repos
What I want to do is
root and root/framework must be separate repos. But
root/framework must be pull only because I have no push access to this repository. I mean I want to pull yii when I pull parent repo, but don't want to push when I push parent repo.
Another problem is, remote dir structure of Yii (root/framework) looks like http://screencast.com/t/mU1TgXuZDv
I need only framework folder's contents. How can I pull only this folder's contents into root/framework ?
To make root/protected/messages separate git repo so that, when I push & pull root git repo, to do it for this one too. In other words, to push & pull with parent one to 2 separate remotes.
To solve second problem, I initialized new repo inside root/protected/messages but now they push & pull separatelly. I mean, I want them to push & pull changes to/from 2 remotes at once. Can't figure out how to do it.
Also I have no idea about first problem.
Any suggestions?
In order to create a separate and independent git repos within a parent git repo, you want to look into Git Submodules (http://git-scm.com/book/en/Git-Tools-Submodules). These basically allow you to create a completely independent git repos inside a directory which by itself is a git repository.
To create the submodule the command is git submodule add git://path/to/gitname.git folder-containing-the-inner-git. Of course you will need to cd into the parent folder before firing this command, which in your case will be root. The git://path/to/gitname.git will be the git url for Yii and folder-containing-the-inner-git will be root/framework.
In order to pull a specific folder of Yii of the entire git repo you might want to try out git checkout as suggested by this question on stackoverflow How to pull specific directory with git. I have never tried this myself.
Also, as of Git 1.7 you can also do a sparse checkout (https://www.kernel.org/pub/software/scm/git/docs/v1.7.0/git-read-tree.html#_sparse_checkout). Although you will still have to fetch the entire repo.
Once you create a separate git repo using git submodules inside root, you will have to push and pull the git inside root/protected/messages seperately. You can however automate this process by creating a git hook (http://git-scm.com/book/en/Customizing-Git-Git-Hooks) for the repo inside root. A hook is a script that can be executed upon specific git events/operations like committing, merging, etc. For a full list of these events you can refer to this page ... http://www.manpagez.com/man/5/githooks/
It seems that there is no event for a git push or pull. However there is an event for git merge ... post-merge :
This hook is invoked by git merge, which happens when a git pull is
done on a local repository. The hook takes a single parameter, a status
flag specifying whether or not the merge being done was a squash merge.
This hook cannot affect the outcome of git merge and is not executed,
if the merge failed due to conflicts.
This hook can be used in conjunction with a corresponding pre-commit
hook to save and restore any form of metadata associated with the
working tree (eg: permissions/ownership, ACLS, etc). See
contrib/hooks/setgitperms.perl for an example of how to do this.
So you can write a simple bash script like :
cd root/protected/messages
git pull origin master
So everytime you pull from the outer repo in root this script will get fired and you will be able to pull the contents of your inner repo as well. However, this will happen on every merge, not just the merges that happen on a pull so you might want to be careful.
Hope this helps.
You may try more straightforward way:
Init your git repo in root;
Add your root/framework to .gitignore in it;
Go to root/framework and init new git repository there;
You will have matroshka styled repos. But, to be frankly, they will be harder to support than git-submodules solution, since root repo does not aware about other repos at all, and all pushesh, pulls need to be done separately inn each repo.

GIT Fetching Multiple Repository's

I have a user github.com/userName that has 50+ Repositories that I would like to clone into a single dir on my Windows PC. What would be the best way to do this?
One way would be to create one more repo in which you declare your 50+ repos as submodules.
That way, you would be able to initialize/clone your 50 repos with a
git clone --recursive your_main_parent_repo
(See "How to git clone including submodules?")
Don't forget to commit and push your main_repo when you have committed and push any of your submodules though.

Resources