Skip to content

inspired2/git_learning

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 

Repository files navigation

Git settings layers

System - All users Global - Current user Local - Current repo

Git config:

git confit --global user.name "Alex Chepur" git config --global user.email [email protected] git config --global core.editor "code --wait"

Same config can be made in single file:

git config --global -e

SSH authentication config

1: Create ssh key (if not yet created) ssh-keygen 2: Add public key to github account. On linux keys are stored at /home/<username>/.ssh After that one can refer to git account as: [email protected]:<username>/<repository_name.git>

Config for handling EoL (end-of-line):

EoLs are handled differently in different systems

git config --global core.autocrlf input //'input' for mac or linux, 'true' for windows

Init new repository

in working repo folder: git init // creates .git folder in working folder. Git stores here info about project history

Basic git workflow

When we're ready to save a snapshot of a project - we make a commit Intermediate step in this process is staging - it allows to view all of the progress before commiting it Here we can delay some files for a later commit.

File staging

Newly created files are not tracked by git. To track them we need to explicitly add them to tracking This can be done automatically by some IDEs; git add <file.name> // track a files git add .// track all ftracking files in current folder git add <file1>, <file2> // track list of files If a file was changed after staging we'll need to stage it again for the changes to be saved

Commiting staged files

git commit -m "<Message>" If we commit without a message: git commmit a file will be opened where we type messages

Gitignore

File .gitignore must be in root folder of the project it contains files and folders that should not be staged/commited if the file/folder is already commited adding it to .gitignore doesn't prevent it from tracking in git in that case we must remove it from staging area(index): git rm --cached -r dir/ // -r flag means delete recursively all that is inside dir There are templates of '.gitignore' for different PLs on www.github.com/github/gitignore/

Git status

git status // full status (verbous) git status -s // comprehansive status

Inspect changes

git diff --staged // changes in staged area compared with commited area git diff // compare working dir and staged area

Difference between exact commits:

git diff HEAD~2 HEAD // show what files were modified between last commit and two steps behind with modifications //we can use --name-only or --name-status arguments to show less info

Inspect logs

git log // log containing commits and messages provided with commits git log --oneline // shorter version git log --reverse // in reverse order (latest first) git log --oneline -- <file.name> // see all commits that touched 'file.name'

Inspect commit

git show <commit_id> // commid id can be first letters of hash git ls-tree <commit_id> // list all the files in a tree of the commit git show HEAD~2 // inspect the commit that is 2 steps behind the last one (last one is specified as HEAD) git show HEAD~2:<path/to/file.name> // inspect the final version of the file in particular commit git show HEAD~2 --name-only // all files that were modified in this commit(added/modified/deleted) git show HEAD~2 --name-status //show what type of modifications were made with files (addition or creation or deletion)

Undo changes

git restore .// undo all the changes in the working folder - replace all local files that has been staged with staged files git clean -f // remove all untracked(unstaged) files

Removing files

git rm <file.name> // remove file BOTH from staging area and working dir, although it still can be in history(previously commited), in that case we must commit the change(commit the deletion of the file) - git commit -m "deleted a file file.name"

Restoring a file

git restore --source=HEAD~1 file.name // --source=HEAD~1 means the commit previous to last one (when we deleted file.name and commited the deletion) //restored file appears as a new file and still needs to be staged and commited if necessary

Inspect full state of some previous commit

git checkout <commit-id> // go to this commit (in HEAD detached mode). We can only inspect files in this mode. If we make some changes we should create a new branch // otherwise all changes will be lost

Recover removed file from previous commit

git log --oneline -- <file.name> // see all commits that touched removed file. The last commit depicted is obviously the commit in which the file was deleted so we need to look for the file in the previous commit. git checkout <prev_commit_id> <file.name> // this will restore the file to working directory and add it to the staging area. //We still have to commit restored file: git commit -m "restored <file.name>"

Find author of changes:

git blame <file.name>

Bookmark

git tag // see all tags in history git tag v1.0 git tag v0.1 <commit_id> //tag a commit in history //we can later use tag: git checkout v1.0 git tag -d v1.0 //delete tag

Annotated tags

git tag v2.2 -m "message"

BRANCHES and branching

A branch is an isolated workspace For example we can make a branch to start to fix a bug and later (when bug is fixed) merge this branch with master branch Master branch must be as stable as possible so that it can be deployed anytime

EXAMPLE WORKFLOW FOR BUGFIX

First create new branch: git branch <branchname> List all branches: git branch Creating new branch doesn't switch to it automatically. We should switch explicitly: git switch <branchname> We can combine creation and switching to a new branch: git switch -C <new_branchname> When we create a branch locally it is not created at the repository (if some) automatically. We can create a branch in the repo (i.e. github) and set our local branch to track this remote branch: git switch -C <branch_name> origin/<branchname>//This also should be done when cloning remote repo, because only master branch is cloned. So we must create a branch and set it to track remote branch as in the previous command.

Rename branch: git branch -m <oldname> <newname> If we're currently on a new branch and commited some changes those changes are observed only on this branch(isolated) If we switch back to master branch the commits that had been made from new branch will not be observable with git log To view the commits from all branches: git log --all

Removing branches

git branch -d <branchname> // This will delete the branch if it will have been already merged with master branch Otherwise there will be an error. To force removal without merging: git branch -D <branchname>

Comparing branches

git log master..<branchname> // See all the commits that are in but not in master git diff master..<branchname> // See actual changes in branches. We can still use --name-only or --name-status to see less info.

Pushing branches

To configure remote repo git should push to: git remote set-url origin [email protected]:<git_username>/<git_repository.git>

To push to newly created repository: git push --set-upstream [email protected]:<git_username>/<git_repository.git> master

Branches (except master branch) are private unless we push them to the repository. To push a new branch to the existing and connected repo: git push -u origin <branch_name>

Stashing

Stashing means storing in a safe place. In terms of git stashing is needed when we've done some changes and need to switch to another branch but we don't want to commit those changes. If we switch without stashing all changes that are in the working dir and staging area will be lost. So to preserve changes we need either to commit or stash them. git stash push -m <message> //this will stash all changes but if we created some files and haven't commited them yet - they won't stash as they are not tracked yet. If we want to stash all (even still untracked files): git stash push --all -m <message>// --all can be minimized to -a: git stash push -am <message> To see stashed git stash list // show all stashes with id's git stash show <stash_id> To apply stash: git stash apply <stash_id> // applies specified stash to the working directory (still needs to be commited) To remove stash: git stash drop <stash_id> git stash clear// remove all stashes

Merging

Merging is bringing changes from one branch to another 2 types of merges:

Fast-forward merges

3-way merges

Fast-forward merge

Used when the changes are linear and we just need to bring HEAD to the point in the new branch we want to merge

3-way merge

Is used when there were some changes(commits) in the master branch after the new branch was created. In that case we cannot just move HEAD to new branch as it doesn't include the changes in the master branch In a 3-way merge a new commit is created that combines changes from both branches 3-way merges might be more convinient to track and revert changes To disable possibility of fast-forward merges: git config ff no //repo level git config --global ff no //for all repos

Merging

To merge a branch to master we must be on master branch git merge <branch_id> //merge <branch_id> to master branch Fast-forward merging is used when possible by default. To use 3-way merging we must prohibit fast-forward with --no-ff: git merge --no-ff <branch_id> To view a list of branches that have been already merged: git branch --merged To view unmerged branches: git branch --no-merged Normally we should delete merged branches. This will prevent confusion: git branch -d <branch_id> To delete unnecessary branch from origin: git push -d origin <unnecessary_branch>

Merge conflicts

When we merge branches and there are some changes to the same file in both branches a merge conflict happens and we have to resolve it. For each file we should decide whether to keep changes only from master or new branch or keep both changes. If we're in the middle of the merge process and want to abort merge: git merge --abort // this reverts all changes during merge

Undo merge

There are situations when merge must be reverted (i.e. it introduced new bugs) It can be done in 2 ways

  1. Remove the merge commit as it was never there. This clears all history about this merge in all users history that follows this repo.
  2. Make new commit that cancells previous commit that merged branches.

RESET

This will move HEAD to the specified commit. Later GIT will automatically remove 'abandoned HEAD' as it will no longer point to any commit. git reset --hard HEAD~1 // Move HEAD one step behind current commit and replace all in current working directory (removing all that doesn't match new HEAD). Other options are --soft (leave staged and working dir content of current state) and --mixed (only working dir stays untouched)

REVERT

This will make new commit that reverts changes git revert -m 1 HEAD // '-m 1 HEAD' means one step from HEAD on the master branch

Rebasing

Rebasing rewrites history - thus it must be used only when there are no other users commiting to this repo. Rebase simply moves a pointer to the parent commit (from which started the new branch) to the HEAD of master so that history becomes linear. And the HEAD pointer is moved to the last commit of the new branch. git switch <new_branch> // Rebase MUST be performed from the branch that is to be merged with master branch git rebase master // This will only make commits history linear we still need to merge with master. git switch master // Merging is made from master branch git merge <new_branch> There can also be conflicts during rebasing. In this case GIT will offer to resolve them. To continue after resolving: git rebase --continue To abort rebase: git rebase --abort

Cherry Picking

When we merge a branch - we merge all commits. Sometimes we want to merge a particular commit without merging all the rest. This is called cherry picking. From master: git cherry-pick <commit_id> We still need to commit: git commit -m "cherry picked"

Picking files from another branch

git restore --source=<branch_name> -- <file_name> git commit -m "copied a file <file_name> from <branch_name>"

TEAM WORKFLOW

A project can be maintained by several collaborators. All of them might have rights to make commits(push the commits) to centralized repositories (i.e. github) In that case they all work with storage directly(push local commits to github repository). Anothe workflow is to have maintainer of the project (maintainers). They are the only persons to have direct access to repository. In that case people that contribute to the project fork the repository and work with it. Forked repository is also available for the maintainer(s). When contributor is ready to share the update he sends a pull request to the maintainer so that he can review the code and merge it to the main repository. This prevents untrusted collaborators from making changes to the main repository. Collaborators in github are managed in SETTINGS -> ACCESS -> Invite a collaborator and send an invitation. When invitation is accepted by the collaborator he is able to push to the repository. Then the collaborator has to clone the repository to his/her local machine and work with it commiting and pushing commits to the github.

LOCAL vs REMOTE

Local repository is our local machine git repository. It has it's own history. When someone pushes his commit to the remote repository, all the other collaborators don't receive and update their local git history automatically. Here we have 2 HEADS:

  1. MASTER - our local latest commit
  2. origin/MASTER - remote repository head position

To do this we need to fetch: git fetch Fetching doesn't update our working directory, it just adds a commit to our local history. So literally we'll have A(MASTER) <- B(origin/MASTER)

To bring the changes to our working directory we need to merge B into A. From master: git merge origin/master

Fetching and merging can be combined in pull

PULL

git pull git pull --rebase

PUSH

git push origin Push might not work if our local history diverts from remote (local MASTER is pointing to a different commit than origin/master points to. Such situation can occur when someone else pushes a commit ahead of you) To handle this issue we must first pull to merge newer commits from origin and then do a push

Releases

Github allows special fiture - host a precompiled binary of the project A release binds to the commit.

Contributing to open-source

We can clone a project directly on github using Fork option. Then we clone to local machine using git clone <url> We can then start development. Forked repository is not connected directly to original repository. To keep our forked project up-to-date we must add original project's origin: git remote add <a_name_for_base_repo(arbitrary)> <original_project_url> We can rename with: git remote rename <old_name> <new_name> And delete the link: git remote rm <repo_alias_name> If we add a new branch and push it to our forked repository we can then make a pull request on github site and select base repository (original project) as a target. The maintainer will receive this pull request. To get latest commits from base repository we can use newly added base remote name: git fetch <base_repo_name> We could be behind in commits so we might need to merge base branch into our local branch git switch master && git merge base/master And still we need to push changes to our git repository(forked) If we have another branches we might want to keep them in sync with base also, so we'll need to merge master into this branch: git switch bugfix && git merge master

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published