paulgorman.org/technical

Git

(2019)

The Pro Git book is very helpful. Its authors, Scott Chacon and Ben Straub, generously publish it under a Creative Commons license.

Git is a distributed version control system. Branching and merging is far easier than with traditional VCS’s.

$ man git
$ man gittutorial
$ man git-help
$ git help
$ git help [commit add etc]

Create a new repo:

$ cd myproject
$ git init
$ git add .
$ git status
$ git commit -em "Initial import."

Changes are added to a cache/staging area before being committed. Files can be added individually before being committed as a second step, or the add-all-commit can be done as one step:

$ git add foo.txt
$ git status
$ git commit
$ git commit -aem 'Fixed caching (issue 4321).'

Keep the first line of the commit message short — fewer than fifty characters. Include an additional details in subsequent paragraphs separated by a blank line. The -e flag invokes the editor to compose a commit message:

$ git commit -e

Pull the diffs for the staged changes directly into the commit message editor:

$ git commit -v

git-commit(1) says:

Note that this diff output doesn’t have its lines prefixed with #. This diff will not be a part of the commit message.

Best of all:

$ git commit -ve

Unstage a file added to the cache but not yet committed:

$ git rm --cached foo.txt

Revert a changed or deleted file:

$ git checkout -- foo.txt

(A bare double-dash “ – ” avoids ambiguity by separating options from a list of arguments.)

Discard all local working changes:

$ git reset --hard HEAD

Remote Repositories

Create a remote origin repo:

$ ssh example.com mkdir ~/repo/myproject
$ ssh example.com git init --bare ~/repo/myproject
$ cd myproject
$ git remote add origin ssh://example.com/~/repo/myproject
$ git push --set-upstream origin master

At some point --set-upstream stopped working. Instead:

$ git branch --set-upstream-to=origin/master master

Clone a remote repo:

$ git clone ssh://example.com/project

Pull updates from a remote:

$ git pull [remote]

Additional remotes:

$ git remote -v
$ git remote add mynewremote ssh://example.com/~/foo
$ git push mynewremote

Add Github as an additional remote:

$ curl -u 'pgorman' https://api.github.com/user/repos -d '{"name":"myproject","description":"This is my project."}'
$ git remote add github https://github.com/pgorman/myproject.git
$ git remote -v
$ git push github master

Show status of a particular remote:

$ git remote show <remote>

Unlink a remote repository:

$ git remote remove github

Reviewing Logs and Comparing Changes

$  git log --stat

commit 47e95939843d35906c26032338727f98a901f7a2
Author: Paul Gorman <me@example.com>
Date:   Thu Aug 9 22:04:56 2018 -0400

    Spelling.

  zerapis.txt | 6 +++---
  1 file changed, 3 insertions(+), 3 deletions(-)

commit c11ff2d1c0d1fe0f0f6e0634c503b0a917c8834e
Author: Paul Gorman <me@example.com>
Date:   Thu Aug 9 21:10:31 2018 -0400

    Moving to markdown.

  zerapis.txt | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 277 insertions(+)

$  git log

commit 47e95939843d35906c26032338727f98a901f7a2
Author: Paul Gorman <me@example.com>
Date:   Thu Aug 9 22:04:56 2018 -0400

    Spelling.

commit c11ff2d1c0d1fe0f0f6e0634c503b0a917c8834e
Author: Paul Gorman <me@example.com>
Date:   Thu Aug 9 21:10:31 2018 -0400

    Moving to markdown.

$  git log  --pretty=oneline

47e95939843d35906c26032338727f98a901f7a2 Spelling.
c11ff2d1c0d1fe0f0f6e0634c503b0a917c8834e Moving to markdown.

$ git log --all --graph --oneline --decorate
* 2a33954 (HEAD -> master, origin/master) Server gives each game an ID.
* 6d73f85 Draw board by JS.
* 817fe58 Started Go web server.
* f579205 Tinkering with UI.
* 3aa1cd4 Visually indicate selected tool.
* ca1b186 Client-side stuff works.
* dcd844c Initial import.

Review commit logs, and compare two commits:

$ git log --stat [master origin foo etc]
$ git diff e274 47c9

Commits are identified by 40-hexadigit hashes. We can refer to a commit by the first few characters of the hash, where there’s no ambiguity.

Show changes over time for a particular file:

$ git log -p myfile

Search when a particular string changed (a.k.a., Git’s “pickaxe” option):

$ git log -S foobar

Diff changed files have not yet been staged/cached:

$ git diff

Diff staged/cached files:

$ git diff --cached

Diff HEAD with the previous commit:

$ git diff @~..@

or: $ git diff HEAD\^ HEAD

Branches and Merging

Branches are named. The default branch is ‘master’. The tag ‘HEAD’ refers to the tip (latest commit) of the current branch.

$ git branch
$ git branch --list
$ git branch testbranch
$ git checkout testbrach
$ git checkout master
$ git branch --delete testbranch

If we want to switch branches without committing the work-in-progress in our current branch:

$ git stash
$ git stash list

Restore stashed files once we switch back to the original work-in-progress brach:

$ git stash list
$ git stash apply [stash@{n}]

Merge a branch back into master:

$ git checkout master
$ git merge testbranch

Resolve merge conflicts:

$ git mergetool

or specify the tool:

$ git mergetool --tool=gvimdiff

Config Files

~/.gitconfig has per-user settings.

/etc/gitconfig is global for the box.

Show effective settings:

$ git config --list --show-origin

~/repo/myproject/.git/config has per-project settings.

~/repo/myproject/.gitignore sets per-project list of files to ignore. Wildcards can be used.

Reviewing a Github merge request

https://help.github.com/articles/checking-out-pull-requests-locally/

  1. Under the repository name, click Pull requests.
  2. Select a pull request from the list of pull requests.
  3. Near the bottom of the pull request, in the merge box, click “command line instructions”. Follow the instructions.

For example:

Check out a new branch and test the changes:

git checkout -b makhidkarun-master master
git pull https://github.com/makhidkarun/travellercharactergenerator.git master

Merge the changes and update GitHub:

git checkout master
git merge --no-ff makhidkarun-master
git push github master

Tagging

https://git-scm.com/book/en/v2/Git-Basics-Tagging

Tags mark specific points in a repo’s history as important. Use this to label a particular commit as a major version (v2.0), for example.

$ git tag
v1.0
v2.0

$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5

$ git tag -a v2.0 -m "Release 2.0 finalizes the new network features."

Or, retroactively tag a previous commit:

$ git tag -a v1.2 9fceb02

By default, git does not push tags to remote servers. Push one or all tags like:

$ git push origin v1.5
$ git push origin --tags

Not Covered

rebase, tags, blame, pickaxe, bisect