1. Synchronising SVN and Git
  2. Configuring Jenkins CI to work with Git on Ubuntu
  3. To check out: Using Git on Windows
  4. My understanding of SVN and Git
  5. statgit - generate Git development statistics
  6. Getting Git to work over SSH in Windows

Nifty aliases

Latest 20 commits, with git latest:

git config --global alias.latest "log --pretty='%C(yellow)%h %C(cyan)%cd %C(green)%aN%C(auto)%d %Creset%s' --graph --date=relative --date-order -20"

Latest 5 tags, with git latest-tags, using version order:

git config --global alias.latest-tags "for-each-ref refs/tags/ --count=5 --sort=-version:refname --format='%(refname:short) - %(contents:subject)'"

Things SVN can do that Git can’t

  1. Checkout into a non-empty directory; you have to checkout into a temporary directory, move the .git folder into the non-empty directory, and run a git reset --hard
  2. Add an empty folder. It’s impossible in Git! .keep files everywhere!
  3. Store passwords on Windows without having to first install some horrible abomination of Cygwin/credential stores/SSH agents, or having to use the GUI client. (Setup SSH for Git and updating Git to use SSH instead of HTTPS)
  4. Display --help information without opening up a man page or a web document (if using Windows?). The --help flag should only print out a summary of help information to the command line.
  5. Keep track of resolved conflicts in other branches when merging the same branches together later on (unless rerere is enabled, which it isn’t by default).
  6. Merge any branch into any other branch without later breaking history. In Git you can’t ever merge a branch into another branch because this will mess up history, and possibly cause a commit loop in the future.
  7. SVN can never have a commit loop unless you’re really trying hard (and editing metadata manually).
  8. Have multiple mainlines. In Git you can only ever have one mainline otherwise you risk having commit loops.
  9. Keep track of which branches a commit has been on. In Git, branches are entirely local to developers, and once they are merged and deleted remotely the history is completely lost (unless a non-fast-forward merge, in which case you’ll have a commit stating there was a merge), because the commits are replaced into the target branch. The best case scenario is <a href=”http://stackoverflow.com/questions/4535251/show-the-original-branch-for-a-commit”

    if you still have the branch in your local repository</a> or the branch has not been deleted remotely yet.

  10. Do more than one reverse merge from a previous commit, without having to perform an intermediary commit. “revert is not possible because you have unmerged files.” You would need to use git revert --no-commit instead.

Things you should never do

  1. git checkout branch; git merge master
  2. git push; git rebase
  3. git merge (always use --no-ff, I don’t know why this is even a Git default)

Branching

Create a branch:

  1. git branch (new-branch-name) - create a new branch, does not switch to branch
  2. git push origin (new-branch-name) - ??
  3. git checkout (new-branch-name) - switch to branch and update local copy to branch
  4. git commit -p - commit changes to local Git
  5. git push --set-upstream origin (new-branch-name) - push local Git changes to remote Git

Switching branches:

  1. git checkout master - switch back to master and update local copy to master
  2. git pull - download remote Git to local Git

Merge branch back in:

  1. git checkout master - switch back to master and update local copy to master
  2. git pull origin master - update local Git from remote Git
  3. git merge (new-branch-name) - do the merge from the given branch (I don’t know what happens with conflicts!)
  4. git push origin master - push local Git to remote Git

Merge two different branches (e.g. you are working on target and want to merge in branch source):

  1. git checkout (target-branch-name) - switch back to master and update local copy to master
  2. git pull origin (target-branch-name) - update local Git from remote Git
  3. git pull origin (source-branch-name) - update local Git from remote Git, merge in branch
  4. git merge (source-branch-name) - do the merge from the given branch (use git mergetool to handle unresolved conflicts)
  5. git push --set-upstream origin (target-branch-name) - push local Git to remote Git

Revert a branch merge on another branch without destroying the commits used elsewhere (technically just reverse merging):

  1. git checkout (target-branch-name)
  2. git revert HEAD^ - ^ means revert back the last commit on this branch
  3. git revert HEAD^^ - ^^ means revert back the second-last commit on this branch (Git cares not about the order of commits on a branch, only individual commits with no relationship to each other!)
  4. git commit && git push - add commit message, push the reverse merge to remote Git

Other commands:

  1. git merge --abort - revert a merge
  2. git diff --cached myfile.txt - see the diff of a staged file (i.e. already been resolved)
  3. git reset --hard - throw away all local changes including any committed, but unpushed, changes
  4. git checkout myfile.txt - analogous to svn revert myfile.txt

Merging with TortoiseMerge

I really like TortoiseSVN’s merge tool, and with a bit of wrangling you can get Git to use it too.

Add the following files to Program Files (x86)/Git/share/git-gui/lib/mergetool.tcl just before the error_popup [mc "Unsupported merge tool '%s'" $tool] block:

tortoisemerge {
    set cmdline [list TortoiseMerge.exe -base:"$BASE" -mine:"$LOCAL" -theirs:"$REMOTE" -merged:"$MERGED"]
}

And then you can run GUI merges using git mergetool -t tortoisemerge.

Your configuration specifies to merge with the ref ‘branch’ from the remote, but no such ref was fetched.

~$ git checkout my-branch
Switched to branch 'my-branch'
Your branch is behind 'origin/my-branch' by 3 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

~$ git pull
Your configuration specifies to merge with the ref 'my-branch'
from the remote, but no such ref was fetched.

This is secret Git speak for “your remote branch no longer exists”. Try running a git remote prune origin to remove all branches that no longer exist on remote.

Having two remote repositories

git clone https://github.com/original/foo
git remote add thirdparty https://github.com/better/foo
git push -u thirdparty master
git pull -u thirdparty

Getting the Github patch for a commit

Append .patch to the end of the commit URL, e.g. https://github.com/soundasleep/cmis/commit/70303e60d437c1c0ee650bcf820c3a13dd4782d1.patch

Revert a merge before it’s pushed

You have to use one of:

  • git reset --hard COMMIT_HASH
  • git reset --hard HEAD~1 (thanks @charliesome)

Git LFS conflicts from changing tracked assets

$> git reset --hard
Encountered 1 file(s) that should have been pointers, but weren't:
        core/assets/tile1.png
HEAD is now at ...

$> git pull
Updating aaa..bbb
error: Your local changes to the following files would be overwritten by merge:
        core/assets/tile1.png
Please commit your changes or stash them before you merge.
Aborting

The only way I found to fix this was to git rm --cached core/assets/tile1.png and then immediately git add core/assets/tile1.png, and then submitting this as a commit git commit. (via StackOverflow)

Note that GitHub doesn’t like displaying this commit:

image