Thursday, September 22, 2016

Notes on using git and github

Everybody knows about github and what an amazing resource it is. This post is about using git with github.

Fork what you're interested in on github. In the following user is your username, repository is the repository you forked.
git config --global core.editor <your_favorite_editor>

You may want to modify the EOL settings to match your preferences and platform.

git clone http://github.com/user/repository.git
cd repository
git config user.name "user"
git config user.email "user@users.noreply.github.com"
git remote add upstream https://github.com/originaluser/repository.git

To integrate new changes from the upstream repo into yours:

git fetch upstream
git rebase -i upstream/master

If there are redundant commits, 'squash' them in the first "interactive" message. The -i is important; otherwise you'll get stuck with a bunch of redundant commits.

If there are any conflicts (changes to the same general area of code, even if just adjacent, or even if equivalent), you will be dropped to the command prompt commit by commit. Edit the conflicting file as it should be, removing any >>>>> or <<<<<. When satisfied, git add thefile and git rebase --continue. They will be applied in a new commit.

Similarly if you want to create a new branch for your own use:

git checkout -b branch

To switch branches at any time (without uncommitted changes), just omit the -b. If you want to instead create the branch at a previous commit, add that branch hash at the end.

Be sure to push any changes to the master branch to github before changing to other local branches. Then pull from github before rebasing.

Then you can rebase as above with the other branch. But if the other branch is pushed to github, it is dangerous to push if anyone else is using it. If you're sure they're not, you can git push --force while on that branch (if git config --global push.default simple). If there were any other users there, after pulling, they'd have to blow away their unpushed local commits with git reset --hard origin/branch.

Here is more on rebasing and merging: https://www.atlassian.com/git/tutorials/merging-vs-rebasing/workflow-walkthrough

Or you can move just one commit to the current branch by using:
git cherry-pick <hashcode>

If you need to clean things up: http://stackoverflow.com/questions/5916329/cleanup-git-master-branch-and-move-some-commit-to-new-branch

If you need to "undo" a change made on github, first pull to update your local repo. Then:
git reset --soft HEAD^, and 
git push origin +branchName (see caveats). 

About reverting, resetting etc, see: https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting

To update an existing remote branch from a local branch (which is currently checked out):
git push origin local_branch_name:remote_branch_name
or if the branch names match, do this and it will work in the future too:
git push --set-upstream origin local_branch_name

All in all my experience is that git is vastly inferior to mercurial (hg); git is far more finicky, harder to use and more prone to ugliness, and plus mercurial has nice GUIs from TortoiseHg. All in all, git feels like an advanced patch manager that has morphed into a version control system while mercurial feels like an advanced version control system. But alas, the linux kernel uses git and thus we have github and the rest is history. But I still use mercurial whenever I have a choice.