Some notes about git. As with all my technical posts, some or all of this may be out of date. Consider it, then, courage to believe that there may be a solution to your problem in terms you can understand.

I have a local repository I want to make into a remote repository

Here's our local repository:

local $ git init .
local $ git add .
local $ git commit . -m "- initial commit"

Nice. Now make an empty repo on the remote server:

remote $ git mkdir repo1
remote $ cd repo1
remote $ git init --bare .

Now add the remote repo as a "git remote" in your local repo:

local $ git remote add origin ssh://git.foo.com/git/repo1
local $ git remote set-branches origin
local $ git push -u origin master

Unstaging files

Sometimes I accidentally add files to the index, usually a directory at a time:

$ git add newdir

I need to un-add a temporary file or something like that:

$ git rm --cached newdir/tmpfile

This will remove the file from the index.

Resurrecting files

I accidentally did:

$ git rm filename

To get it back, just check it out again:

$ git checkout filename

Replacing the master branch

If you have a branch (yodawg) you want to make the master branch, do this:

$ git checkout yodawg
$ git merge --strategy=ours --no-commit master
$ git commit -m "- merging yodawg replace into master"
$ git checkout master
$ git merge yodawg

This is from stackoverflow

Merge errors

Sometimes when you do a git pull, you'll have conflicts:

CONFLICT (content): Merge conflict in SomeFile
Automatic merge failed; fix conflicts and then commit the result.

Fix the conflict (edit the file), then when you commit, use the --include (or -i) flag:

$ git commit --include filename

This tells git to add the file into the index first before committing. Once this commit completes, the merge also finishes.

Undoing things

Here's a great resource.

Local changes during merge

Sometimes when you do a git pull you'll have local changes that would be overwritten by the merge:

error: Your local changes to the following files would be overwritten by merge: FILNAME Please, commit your changes or stash them before you can merge. Aborting

To stash your changes for later:

$ git stash save

This will put your changes into a temporary index called the stash. Now you can do your git pull or merge safely. Once the merge is finished, you can pull your stuff back out again:

$ git stash pop

Branching

You're hacking away and want to try something radical. Time to branch:

$ git checkout -b my-experiment
Switched to a new branch 'my-experiment'

That was easy.

What about my local changes?

Let's say you're hacking away and tried something radical and realized that maybe you should have branched those changes. You don't want to commit them to the master branch just yet. Stash your changes:

$ git stash save
Saved working directory and index state WIP on master: e3aabe6 -
last commit subject here
HEAD is now at e3aabe6 - last commit subject here

Your uncommitted changes have been saved in the stash. Now make your branch:

$ git checkout -b my-experiment
Switched to a new branch 'my-experiment'
$ git stash apply
# On branch my experiment
# Changes not staged for commit:
...

And now you have a new branch with your uncommitted changes applied to it.

"not on any branch" after "git checkout (commitish)"

You've branched without a name. Give it a name with:

$ git checkout -b new-branch-name

Tracking remote branches

Assume you have laptop A with master and experimental branches. You've pushed everything to a git server. Now on laptop B you want to "track" the experimental branch:

$ git fetch origin (this pulls down all refs)
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/experimental
  remotes/origin/master
$ git checkout --track origin/experimental

Now experimental is a local branch that tracks/follows the origin/experimental branch.

Alternatively, you can:

$ git checkout -b experimental origin/experimental

Both of these are equivalent: they create a copy of the remote branch and track the remote branch for changes (you can't make a remote branch your own, but you can create a copy and track the remote).

github work

A nice summary of the "git flow"

Renaming files on a case-insensitive filesystem

OS X is moderately case-insensitive. It will show you the case of files, etc., but when you're having the file system look for something by name, any case will do.

I had a file I needed to rename:

lib/BS/API/V1/IPs.pm -> lib/BS/API/V1/Ips.pm

On a case-sensitive file system, it would be easy:

$ git mv lib/BS/API/V1/IPs.pm lib/BS/API/V1/Ips.pm

but in OS X you have to make a temp file; fortunately this does not make any new commits:

$ git mv lib/BS/API/V1/IPs.pm lib/BS/API/V1/Ips.pm.tmp
$ git mv lib/BS/API/V1/Ips.pm.tmp lib/BS/API/V1/Ips.pm

then adjust .git/config:

ignorecase = true

to:

ignorecase = false

Make your commit now. I think you can change ignorecase back to how it was before now that your commit it made.

Removing a commit

$ git revert (commit)

Removing a commit from one file in a multi-file commit

$ git diff (sha1)..(sha1)^ -- (filename) | patch -p1

Changed files in git log

To see the changed files in the log:

$ git log --stat

to see a diff:

$ git log -p

Create a branch without a specific commit

If you have master with commits:

g
f
e
d
c
b
a

and you want to make a new branch without e, do this:

$ git checkout -b new-branch
$ git revert e

Detach subdirectory into separate git repository

This comes from stackoverflow:

Assume you have repository XYZ:

XYZ/
   -ABC/
   -DEF/
   -foo
   -bar

and you want to pull out ABC into its own repository with history. Do this:

  • clone the repo locally:

    $ git clone --no-hardlinks XYZ ABC
    $ cd ABC
    
  • if you have branches you want to preserve, see the stackoverflow article

  • remove everything we don't want:

    $ git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
    
  • remove backup reflogs:

    $ git reset --hard
    $ git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    $ git reflog expire --expire=now --all
    $ git gc --aggressive --prune=now
    
  • remove the subtree from the original repo:

    $ cd ../XYZ
    $ git filter-branch --tree-filter "rm -rf ABC" --prune-empty HEAD
    
  • how to now sync the pruned repo? I don't know

restore one file from stash

Remember that the stash is a branch:

$ git checkout stash@{0} -- path/to/file.txt

github remotes

GitHub provides a special pulls remote "namespace" on the upstream repo, so you can add it as a fetch pattern to your .git/config like so:

[remote "upstream"]
  url = https://github.com/neovim/neovim.git
  fetch = +refs/heads/*:refs/remotes/upstream/*
  fetch = +refs/pull/*/head:refs/pull/upstream/*

convert a working directory into a bare repository

$ git clone --bare -l repo repo.git
$ rm -rf repo