Understanding Git well enough to anticipate its every move.
Marcel M. Cary
Learning a foreign language:
I will assume you:
This is not an intro-level presentation, but you can still learn something if you have not used Git before.
~/Projects/git|master$ git log --format=fuller 2c3c395e commit 2c3c395e84409c278bd7b050877c36d04b952056 Author: Marcel M. Cary <marcel@oak.homeunix.org> AuthorDate: Fri Feb 6 19:24:28 2009 -0800 Commit: Junio C Hamano <gitster@pobox.com> CommitDate: Sat Feb 7 00:45:29 2009 -0800 git-sh-setup: Use "cd" option, not /bin/pwd, for symlinked work tree In cd_to_toplevel, instead of 'cd $(unset PWD; /bin/pwd)/$path' use 'cd -P $path'. The "-P" option yields a desirable similarity to ...
~/Projects/git|master$ git log --oneline 7d233dea 7d233de gitweb: Hyperlink multiple git hashes on the same commit message line 024aa7d system_path(): simplify using strip_path_suffix(), and add suffix "git" 4fcc86b Introduce the function strip_path_suffix() 88e3880 filter-branch -d: Export GIT_DIR earlier 51b2ead disallow providing multiple upstream branches to rebase, pull --rebase d61027b Skip timestamp differences for diff --no-index b94ead7 git-svn: fix parsing of timestamp obtained from svn df5d10a gitweb: Fix warnings with override permitted but no repo override bed5122 Documentation/git-push: --all, --mirror, --tags can not be combined ...
Git Commit IDs are a digest (checksum) of the commit attributes, which cryptographically guarantees that the commit can't be altered.
~$ mkdir example-repo ~$ cd example-repo ~/example-repo$ git init ~/example-repo|master$ touch README.md ~/example-repo|master$ git add README.md ~/example-repo|master$ git commit -m 'Initial commit' [master c714722] Initial commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md
~/example-repo|master$ echo hi > README.md ~/example-repo|master$ git commit -am 'Say hi' [master 016e54b] Say hi 1 file changed, 1 insertion(+)
~/example-repo|master$ git log -p commit 016e54bea7d5803346ed1b57b963fefe3ea22d9d Author: Marcel M. Cary <marcel@oreilly.com> Date: Tue Feb 9 20:16:48 2016 -0800 Say hi diff --git a/README.md b/README.md index e69de29..3b18e51 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +hi commit c714722b9a633a523a982ad5b88374a37683ce1d Author: Marcel M. Cary <marcel@oreilly.com> Date: Tue Feb 9 20:05:58 2016 -0800 Initial commit ...
~/example-repo|master$ echo 'Hello World!' > README.md ~/example-repo|master$ git commit --amend -am 'Say Hello!' [master d2b3e97] Say Hello! Date: Tue Feb 9 20:16:48 2016 -0800 1 file changed, 1 insertion(+)
~/example-repo|master$ git log -p commit d2b3e97df640b0d2a863630af42d35ecb13573cd Author: Marcel M. Cary <marcel@oreilly.com> Date: Tue Feb 9 20:16:48 2016 -0800 Say Hello! diff --git a/README.md b/README.md index e69de29..980a0d5 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +Hello World! commit c714722b9a633a523a982ad5b88374a37683ce1d Author: Marcel M. Cary <marcel@oreilly.com> Date: Tue Feb 9 20:05:58 2016 -0800 Initial commit ...
?
Let's create a visual model for commits.
git log --format=fuller c714722b
~/example-repo|master$ git reflog master d2b3e97 master@{0}: commit (amend): Say Hello! 016e54b master@{1}: commit: Say hi c714722 master@{2}: commit (initial): Initial commit
~/example-repo|master$ git show 016e54b commit 016e54bea7d5803346ed1b57b963fefe3ea22d9d Author: Marcel M. Cary <marcel@oreilly.com> Date: Tue Feb 9 20:16:48 2016 -0800 Say hi diff --git a/README.md b/README.md index e69de29..3b18e51 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +hi
How does Git know which commit is "current"?
~/example-repo|master$ git reflog master d2b3e97 master@{0}: commit (amend): Say Hello! 016e54b master@{1}: commit: Say hi c714722 master@{2}: commit (initial): Initial commit
What's the difference between the reflog and the log?
When collaborating, amending risks introducing redundant versions of a commit into your commit log if your collaborators don't also abandon the superseded commit.
(See "RECOVERING FROM UPSTREAM REBASE" in the git-rebase manual.)
~/example-repo|master$ git checkout -b fill-in-readme Switched to a new branch 'fill-in-readme' ~/Projects/example-repo|fill-in-readme$ git branch * fill-in-readme master
No matter how many files or commits in your
repo,
branching just creates a pointer and updates HEAD.
HEAD is a symbolic ref — a pointer to a branch
~/example-repo|fill-in-readme$ git symbolic-ref HEAD refs/heads/fill-in-readme
refs/heads/fill-in-readme
~/example-repo$ find . | grep refs/heads/fill-in-readme ./.git/logs/refs/heads/fill-in-readme ./.git/refs/heads/fill-in-readme~/example-repo$ cat .git/refs/heads/fill-in-readme d2b3e97df640b0d2a863630af42d35ecb13573cd
A Symoblic Ref used to be a Symolic Link, until Git supported Windows.
~/example-repo$ grep -r . refs/heads/fill-in-readme ./.git/HEAD:ref: refs/heads/fill-in-readme
~/example-repo|fill-in-readme$ cat > README.md <<EOF > Example Repo > ============ > > Hello World! > EOF ~/example-repo|fill-in-readme$ git commit -am 'Fill in the README' [fill-in-readme 30842db] Fill in the README 1 file changed, 3 insertions(+)
Makes master have all changes from both branches
~/example-repo|fill-in-readme$ git checkout master Switched to branch 'master'~/example-repo|master$ git merge fill-in-readme Updating d2b3e97..30842db Fast-forward README.md | 3 +++ 1 file changed, 3 insertions(+)
Suppose instead that master already had additional commits.
~/example-repo|master$ git log --oneline \ --decorate --all --graph * 2545de7 (HEAD, master) Merge branch 'fill-in-readme' |\ | * 30842db (fill-in-readme) Fill in the README * | 2c89b05 Add src |/ * d2b3e97 Say Hello! * c714722 Initial commit
$ git log --oneline master 2545de7 Merge branch 'fill-in-readme' 2c89b05 Add src 30842db Fill in the README d2b3e97 Say Hello! c714722 Initial commit $ git log --oneline ^fill-in-readme master 2545de7 Merge branch 'fill-in-readme' 2c89b05 Add src $ git log --oneline fill-in-readme..master 2545de7 Merge branch 'fill-in-readme' 2c89b05 Add src
README.md
on master
+Contributors
+------------
+
Hello World!
README.md
on fill-in-readme
+Example Repo
+============
+
Hello World!
~/example-repo|master$ git merge fill-in-readme Auto-merging README.md CONFLICT (content): Merge conflict in README.md Recorded preimage for 'README.md' Automatic merge failed; fix conflicts and then commit the result.
~/example-repo|master*+|MERGING$ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: (use "git add..." to mark resolution ) both modified: README.md no changes added to commit (use "git add" and/or "git commit -a")
README.md
<<<<<<< HEAD Contributors ------------ ======= Example Repo ============ >>>>>>> fill-in-readme Hello World!
README.md
Example Repo ============<<<<<<< HEADContributors ------------======= Example Repo ============ >>>>>>> fill-in-readmeHello World!
~/example-repo|master*+|MERGING$ git add README.md ~/example-repo|master+|MERGING$ git commit
Merge branch 'fill-in-readme' Conflicts: README.mdKeep Contributors from master, and keep top-level heading from fill-in-readme.Rebasing
Rebase my pull request??
Scenario
~/example-repo|fill-in-readme$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. ~/example-repo|master=$ git pull --ff-only From http://github.com/mcary/example-repo d2b3e97..2c89b05 master -> origin/master Updating d2b3e97..2c89b05 Fast-forward src/example.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/example.c ~/example-repo|master=$ git log --oneline d2b3e97..2c89b05 2c89b05 Add src ~/example-repo|master=$ git checkout - Switched to branch 'fill-in-readme'Rebase Command
~/example-repo|fill-in-readme$ git rebase master First, rewinding head to replay your work on top of it... Applying: Fill in the READMERebase
→masterHEAD←↓fill-in-readme2c89b052Add src↓d892049Fill in the README↓30842dbdFill in the README↓d2b3e97dSay Hello!Recap
- Immutability
- Amending
- Committing
- Branches
- HEAD
- Merging: fast-forward or non
- Resoling merge conflicts
- Commit exclusion and ranges
- Rebasing
Dreaming in Git
Understanding Git well enough to anticipate its every move.
Marcel M. Cary