Git Crashcourse
ohshitgit because messing up is too ez
WARNING: The terms I use are nonstandard from most other tutorials.
1 Setup Credentials
Setting email and username for local repo or global env
git config user.email "example@example.com"
git config user.name "example"
git config --global user.email "example@example.com"
git config --global user.name "example"
1.1 github remote credential
If you omit the userJY:PACTOKEN
part you will get an error remote: Invalid username or password. fatal: Authentication failed for 'https://github.com/userJY/logicalverification2021.git/'
git remote add origin https://userJY:PACTOKEN@github.com/userJY/blehrepo.git
1.1.1 Saving remote github Credential on local repo
git config credential.helper store
git push -u origin main:main
By pushing to remote repo you will be asked to enter username and password( password is really the auth token you have to generate in github settings).
The above command makes it so the setting is saved.
1.2 Your .gitconfig data
git config --list
delete .gitconfig to reset your config
1.3 Remote Error
remote: Permission to somebdy/bleh.git denied to someGuy.
fatal: unable to access 'https://github.com/somebdy/bleh.git/': The requested URL returned error: 403
1.4 On git push and pull
git push -u origin <SrcLocalBranch>:<TargetRemoteBranch>
git pull origin <SrcRemoteBranch>:<TargetLocalBranch>
2 The process
git add .
git commit -m "some message"
updating to remote repo like github
git push origin main
2.1 Pushing updates to Team repo
git checkout -b Fixedbugbranch
git add .
git commit -m "fixed bugs"
git push origin Fixedbugbranch
You see a push but on the team’s side, they see a pull request(PR).
PR is ran through github actions(CI system) that runs tests.
If accepted, they merge your PR branch with the main branch.
2.2 More depth, Concept
Three layers to know: commit-references(ref), branch-alias(alias), HEAD
- layer 1 - ref : static nodes of the commit tree.
- layer 2 - alias : static names that point to the refs
- alias = name of branch, default branch is “main”
- layer 3 - HEAD : dynamic pointer that can point to alias or refs
Example git tree:
alias(“somebranch”)
🠫
ref(branch_new)
🡑
ref(commit_new) ← ref(commit_old) ← ref(commit_oldest)
🠩
alias(“main”)
⭫
HEAD
Description:
HEAD(layer 1) points to branch alias(layer 2) which points to
commit ref(layer 3).
Aliases(layer 2) always points to the local head(layer 1).
2.3 Creating new Aliases = Creating new branches
Old commits(layer 1) aka non-local-head commits do not have aliases(layer 2) pointing to them but if you do make an alias, they will become a local-head(layer 1) by branching.
Do not confuse the “HEAD” pointer with the “local head of a branch”.
The “local head of a branch” refers to the local head of commit-refs at layer 1.
The “HEAD” pointer refers to the layer 3 pointer.
name | command |
---|---|
ref (layer 1) | git commit - adds a new ref node. Moves HEAD to alias of new node |
alias (layer 2) | git branch - assign an alias to ref node on new branch. Moves HEAD to new alias |
HEAD (layer 3) | git checkout - Moves head pointer to either alias or ref |
Every git node has a ref that looks like 3bed42g14584b3c0c04fdcc4f503346f92be1003
We can point HEAD(layer 3) to aliases(layer 2) like “main” with git checkout main
Switching branch = move HEAD(layer 3) to alias(layer 2) of new branch git checkout someotherbranch
git checkout can
1) switch branch
2) go to older version
Pointing HEAD(layer 3) directly to ref(layer 1), Detached HEAD mode We can point HEAD(layer 3) to ref(layer 1) like “3bed42g1…” with git checkout “3bed42g1…”
If you modify files, then commit. Any change will be discarded if you switch back to main (git checkout main)
To make changes permanent, you have to build a branch by making an alias(layer 2) with your commit(layer 1). git branch SomeName
Why and When do we point HEAD to naked refs The newest version has compatibility issues and you want to build off an old version.
transverse git commit tree using the HEAD pointer. HEAD pointer can point to alias like “main” or refs like “3bed42g…”
“git branch” vs “git checkout -b”
git branch makes a new alias and branch, BUT HEAD stays on current branch
git checkout -b behaves the same as git branch BUT moves HEAD to new branch
3 Remove unstaged changes
git restore .
4 Extras
tags are just renaming refs, they are NOT at the same level as aliases. Meaning if you point HEAD to a tag, you are in a detached head state.
In gitk yellow node HEAD pointer points to blue untagged node(meaning it is not the local head of a branch)git
5 Merging
5.1 Example
Example: clone git project first commit
commit 0382315a65a3fa24595718b3bf141f09a49b6469 (HEAD -> main, origin/main, origin/HEAD)
Author: JY <example@example.com>
Date: Mon Sep 27 16:04:23 2021 -0700
Initial commit
0382315a65a3fa24595718b3bf141f09a49b6469 is the commit on both server and local repo.
- Modify README.md locally (write “hello” to README.md)
$ git log
commit 070f18087be629ba7387a9242af03f85ac656910 (HEAD -> main)
Author: jy <example@example.com>
Date: Mon Sep 27 16:15:11 2021 -0700
update
commit 0382315a65a3fa24595718b3bf141f09a49b6469 (origin/main, origin/HEAD)
Author: jy <example@example.com>
Date: Mon Sep 27 16:04:23 2021 -0700
Initial commit
- Modify README.md on github website. (write “goodbye” to README.md)
remote new head: 3295ca935359bc5fc4e8592c9057d3c3c5cd7a6d
- Notice Remote and Local repo are out of sync now
- Local repo head: 070f18087be629ba7387a9242af03f85ac656910
- Remote repo head: 3295ca935359bc5fc4e8592c9057d3c3c5cd7a6d
- Point of divergence: 0382315a65a3fa24595718b3bf141f09a49b6469
Let’s trying pushing local 070f1 changes to remote anyway
$ git push -u origin main:main
To https://github.com/userJY/gittmp.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/userJY/gittmp.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
It failed as expected
Let’s follow instructions and use git pull
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 641 bytes | 91.00 KiB/s, done.
From https://github.com/userJY/gittmp
0382315..3295ca9 main -> origin/main
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
The above line shows local..remote conflict.
0382315..3295ca9 main -> origin/main
on our console we see we have been automatically put into MERGE mode.
User@WindowsPC MINGW64 ~/Desktop/gittmp (main|MERGING)
If you enter your README.md you will find the below content while in MERGE mode.
Pre-Merge state:
<<<<<< HEAD
hello
Hello
=======
goodbye
Goodbye
>>>>>>> 3295ca935359bc5fc4e8592c9057d3c3c5cd7a6d
Aside: You can even commit this pre-merge state.
This will update local README.md to the above content.
You can even push this new pre-merge state commit to remote github. But clearly you shouldn’t do this as it defeats the entire point of merging!!
Use abort to leave MERGE mode to return to local repo
git merge --abort
5.2 To fix up the MERGE conflicts
Go back to MERGE mode
git pull #back to merge mode
git mergetool #will ask to start default vimdiff
5.3 Non-conflict automerge
image if local was
hello
and remote was
yello
Git pull, would merge by
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 639 bytes | 91.00 KiB/s, done.
From https://github.com/userJY/gittmp
8401a16..d93f27c main -> origin/main
Auto-merging README.md
Merge made by the 'recursive' strategy.
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
5.4 Undo add
- this is before committing
git reset --hard
--hard
means remove modified uncommitted files--soft
means keep modified uncommitted files
WARNING: Calling git reset --hard
AFTER git add .
but BEFORE git commit ...
will DELETE YOUR WORK.
5.4.1 In case of Accidental Deleted Work
In case you did do git reset --hard
AFTER git add .
but BEFORE git commit ...
you can recover files as blobs without file names.
git fsck --lost-found
#script that recovers files and filters file by content like `bayesian net`
cd ./.git/lost-found/other
for FILE in *; do git show $FILE | grep "bayesian net" ; echo $FILE; done
git show a73ff6d1c2bbc01fc2c182ed0c07961969f27c82 > recovered.ipynb
cp recovered.ipnyb ~/recoveredfolder
5.6 Removing untracked changes
git clean -f
You might use this when you did a merge but Ctrl-C or exited out in the middle so now you’re left with temp MERGE files.
6 Git Scenarios
6.1 Creating your git project
Say we spent time building a project locally called A.
We turn it into a git repo after it is finished.
How do we push it onto github?
First we need to create an empty github repo.
But now we have 2 repos with separate histories.
{local} {github}
mkdir A create github repo B
git init A
git remote add origin B
3 types of pulls:
1) git pull origin --no-rebase main
[Nothing happens]fatal: refusing to merge unrelated histories
2) git pull origin --rebase main
[Success]This puts your remote commit B as first then local commit as recent.
B --> A
2) git pull origin --ff-only main
[Nothing happens]fatal: refusing to merge unrelated histories
the default pull uses no-rebase.
6.2 Rebasing
rebasing just means we can reorder our commit history
6.3 remove files after adding .gitignore
Scenario:
- You acidentally pushed .bleh on to github
- Later you commited to local repo a .gitignore to ignore .bleh then synced it with github repo
- Problem: .bleh is still in the github repo
Solution:
git rm -r --cached .bleh
then add,commit and push to github will remove the remote github .bleh file or directory
7 git Vim micro tut for merging
ctrl-w-w to switch screen on 3 way commit
esc-u to undo esc-:diffupdate after undo to rescan difference
esc-:diffget LO to apply Local, left most window esc-:diffget remote to apply Remote, right most window esc-:diffget BA to apply base, top center window
esc-i to insert mode esc-dd to delete line
esc-]-c to move to next conflict esc-[-c to move to prev conflict