39

We're in the process of migrating from Mercurial to Git for our workflow and I have two minor issues.

First, is it possible to "clone" a local repository directly into an empty remote (ssh) dir?

Currently when we create a new website we basically clone our CMS locally, configure it and then we clone it on the central repo and on the webserver (hg clone . ssh://account@server/www). That way we have instant access to push/pull goodness.

This brings me to the second issue, remote deployment.

Currently with Mercurial, I have a simple hooks in the remote repos that execute hg up when a changeset is received.

To do the same with Git I've followed the instructions here: http://caiustheory.com/automatically-deploying-website-from-remote-git-repository but I'd like to keep the .git directory in the website root as it is the case with Mercurial (it's protected by Apache config and I can't export GIT_DIR for all accounts as some have more than one website/repos).

Is it possible to have basically the same setup without separating the working dir from the repos?

suci
  • 178
  • 7
hlidotbe
  • 888
  • 2
  • 9
  • 17

6 Answers6

45

To answer your first question, yes, you can. Suppose the remote directory is ssh://user@host/home/user/repo. This must be a git repository, create that with git init --bare or scp your local repo.git (can be created with git clone) directory to remote. Then do:

git remote add origin ssh://user@host/home/user/repo
git push --all origin

This will push all locally-existing branches to the remote repository.

To get to your next question, you should be able to do the same thing by using a different set of commands. Try these:

$ cd /var/www  # or wherever
$ mkdir somesite
$ cd somesite/
$ git init
$ git --bare update-server-info
$ git config receive.denycurrentbranch ignore
$ cat > hooks/post-receive
#!/bin/sh
git checkout -f
^D
$ chmod +x hooks/post-receive

You would, of course, run the remote/push commands above after this step. You may have to check out a specific branch after doing so, so that the "somesite" clone on the server actually knows which branch to follow. From then on out, pushing to that repository should trigger a re-checkout of that branch.

Yaroslav Nikitenko
  • 1,695
  • 2
  • 23
  • 31
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • as an addition, on the "git push", I'm used to specifying the branch I push onto. So your push statement in my case will read "git push --all origin master" – Igbanam Nov 10 '10 at 09:46
  • If you want to do that, take out the --all or git will push them all anyway. :) – cdhowie Nov 10 '10 at 09:47
  • Thanks for the answer. The first part works fine although I get a warning about updating the current branch when pushing (on a bare repos that goes away). For the second part I'm maybe miss something. After "git init" I had to got into .git otherwise the update-server-info wouldn't work. After that, the post-receive hooks seems to work but doesn't remove files it only marks them untracked (hg update would bring me in the correct state if there were no changes on the remote). – hlidotbe Nov 10 '10 at 10:45
  • Try adding "git clean -fd" right after the checkout in the hook script. Note that this will delete all untracked files that do not match a .gitignore pattern, so make sure any server config files are appropriately ignored if you want to keep them. – cdhowie Nov 10 '10 at 14:12
  • mmh that might work but this means if a user add some files (using ftp) they will be removed. With mercurial the update merges the remote working dir with the new changesets and I get a feedback if it fails (then I have to merge manually on the server but it's rare). For now I'll do without the clean and I'll dig into git when I have more time. Thanks again! – hlidotbe Nov 10 '10 at 17:08
  • No problem. For what it's worth, I use git for deployment, but I have the deployed repository pull from the main repository. Pushing a branch to a non-bare repository when that repository has that branch checked out is just asking for trouble. – cdhowie Nov 10 '10 at 17:10
  • Unlike `hg clone`, the answer to the first question doesn't work if the remote git repo doesn't already exist. See the better answer of @OOPMan for that. – Yitz Nov 11 '14 at 23:48
  • @cdhowie : what If I have only shell access on the server ? I won’t be able to checkout ? – user2284570 Nov 13 '15 at 14:26
  • or less statefully on the local machine `GIT_SSH_COMMAND='ssh -i ~/.ssh/ -l ' git push HEAD:FETCH_HEAD`; after initializing the remote repo, thenafter checkingout FETCH_HEAD remotely – ThorSummoner Aug 20 '18 at 23:55
  • Did you miss 1# git add . 2# git commit ? – Asher Apr 15 '21 at 11:40
  • @Asher No, I didn't. – cdhowie Apr 15 '21 at 23:19
29

I also ran into this issue recently and solved it as follows:

On remote server:

1: Create a directory named /tmp/bare
2: Change to that directory
3: Execute git init --bare

On local machine:

1: Change to your git project directory
2: git remote add bare ssh://user@server/tmp/bare
3: git push --all bare
4: git remote remove bare

On remote server:

1: git clone /tmp/bare /path/to/your/clone

On local machine:

1: git remote add origin ssh://user@server/path/to/your/clone

This is a little involved, but it works and does not require setting any weird flags or instructing git to override its default behaviours. It is hence quite safe.

OOPMan
  • 510
  • 4
  • 8
4

This answer is good but I was not able to get it to work for me. The following code from this link did http://thelucid.com/2008/12/02/git-setting-up-a-remote-repository-and-doing-an-initial-push/. On the remote run

mkdir my_project.git
cd my_project.git
git init --bare
git-update-server-info # If planning to serve via HTTP

Locally on an existing repository that already has at least one commit run

git remote add origin git@example.com:my_project.git
git push -u origin master

I hope this helps anyone that had problems with the other answer.

AmaDaden
  • 994
  • 8
  • 13
3

Easiest git equivalent to hg clone . ssh://account@server/www is:

rsync -avz . ssh://account@server/www/reponame

In fact, I have added this line to ~/.bash_aliases to mirror any directory anywhere:

alias mirror="rsync -avz . ssh://account@server`pwd` --delete"

It could prove dangerous if you happen to be in a special directory like /dev or /bin. Be careful.

jlettvin
  • 1,113
  • 7
  • 13
presto8
  • 487
  • 5
  • 8
1

I agree with, and improve on presto8 by deleting unmatched files.

rsync -avz . ssh://account@server/www/reponame --delete
kleopatra
  • 51,061
  • 28
  • 99
  • 211
jlettvin
  • 1,113
  • 7
  • 13
0

Just to give you an alternative, you can use:

git remote set-url origin git://other.url.here

These also work if your local git respository is pointing to another remote repository

dani24
  • 2,108
  • 2
  • 26
  • 28