Using git with local folders
‘Git’ and ‘GitHub’ are so synonymous nowadays that you’d be forgiven for thinking you can’t have one without the other. I just realised that I personally don’t know how to use git its online counterpart, as I’ve only ever experienced using
push and the like with GitHub URLs. So today, we learn how to do local git together.
Make a local repo
This demo is on Windows.
Make a new folder for your git experiments somewhere, and open a Git Shell in there (mine is
/c/gitexp). We’re going to make a folder with a single file,
file.txt containing ‘Hello World’. You can do all of the following in Windows GUI if you prefer:
$ mkdir NewRepo $ cd NewRepo $ echo Hello World > file.txt
Let’s set up git in here:
$ git init $ git add -A $ git commit -m 'init NewRepo'
Clone your local repo
Right away, that repository is something we can clone to anywhere else on the PC. We can find out from running
$ git help clone in the section Git URLs that to refer to local repos, you can use one of these syntaxes:
/c/gitexp/NewRepo or file:///c/gitexp/NewRepo
So, pop back out to your git experiments folder and clone that repo into a repo with a new name:
$ cd .. $ git clone /c/gitexp/NewRepo NewRepoClone
cd into your cloned directory and check for remotes, you’ll see that the
origin is already set up:
$ cd NewRepoClone $ git remote -v origin C:/gitexp/NewRepo (fetch) origin C:/gitexp/NewRepo (push)
…I think it’s neat that it already knows this!
Make changes and try to push them
First, let’s make changes in
NewRepoClone and commit them:
$ echo Hello World Wide Web > file.txt $ git add -A $ git commit -m 'Expanded on the Hello message' $ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working directory clean
We are going to come across a fun thing here. If you try to
push your changes to origin,
git will refuse. Then I will explain why.
$ git push origin master Counting objects: 3, done. Writing objects: 100% (3/3), 284 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) remote: error: refusing to update checked out branch: refs/heads/master remote: error: By default, updating the current branch in a non-bare repository remote: error: is denied, because it will make the index and work tree inconsistent ...<Snip>... To C:/gitexp/NewRepo ! [remote rejected] master -> master (branch is currently checked out) error: failed to push some refs to 'C:/gitexp/NewRepo'
The most informative part of this long error message is near the end: “branch is currently checked out”.
The crux of the problem is that git knows that the currently-checked-out branch in the origin (
master. A good analogy is that you’re ‘logged in’ to
master there. It fears that by pushing changes to a branch that someone else (you) might be working on, things will get messed up.
How to fix the problem and push your changes for real
Really, your origin should be a ‘bare repository’, and I’ll explain what that means later. But to make the push just work in our instance, there is a pretty good solution. We can check out a different branch in the origin, like this:
$ cd ../NewRepo $ git branch idle $ git checkout idle
Now we can go to the clone and actually push our changes:
$ cd ../NewRepoClone $ git push origin master Counting objects: 3, done. Writing objects: 100% (3/3), 284 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To C:/gitexp/NewRepo 506def7..e2cdc5c master -> master
About bare repos
When you push to GitHub, the receiving
origin repo is really a ‘bare repo’. This means that it doesn’t contain all the working files, it just contains the stuf you’d normally find in the
.git folder. So it’s kind of a server-only repo, more like SVN. Here is a great article about bare repositories.
You can clone as a bare repository and use that as the dedicated origin to avoid the problems above. By convention, a bare repo directory has a
.git extension (like in a GitHub URL).
$ cd /c/gitexp $ git clone --bare /c/gitexp/NewRepo NewRepo.git
Now you can use your
NewRepo.git as the origin and have no problems pushing/pulling from it. The only downside is that you can’t do work in the origin, but you could always just clone another copy to somewhere else instead :)