Comprehensive Git Tutorial for Ubuntu
- Introduction to Git Git is a distributed version control system designed to handle projects of any size with speed and efficiency. It's widely used for source code management and can track changes in files, enabling multiple people to collaborate on a project seamlessly.
- Installing Git on Ubuntu First, ensure your package list is up-to-date and then install Git:
sudo apt update sudo apt install git
Authentication with Github Repos
GitHub no longer supports password authentication for Git operations. Instead, you need to use one of the recommended authentication methods, such as SSH keys or personal access tokens (PATs). Here’s how you can set up both methods:
Method 1: Authentication Using SSH Keys
Generate an SSH Key Pair (if you don’t have one already):
ssh-keygen -t ed25519 -C "your_email@example.com"
Follow the prompts to save the key. By default, the key will be saved in ~/.ssh/id_ed25519.
Add the SSH Key to the SSH Agent: (Optional)
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Add the SSH Key to Your GitHub Account:
Copy the SSH key to your clipboard:
cat ~/.ssh/id_ed25519.pub
Go to GitHub SSH and GPG keys settings. Click "New SSH key," give it a title, and paste the key. Now save it.
Create a Repository on git hub and copy its SSH address.
Clone the Repository Using SSH:
git clone git@github.com:username/repository.git
-
Configuring Git After installation, set up your Git username and email. These details will be associated with your commits.
git config --global user.name "Your Name" git config --global user.email "your.email@example.com"
Verify the configuration:
git config --list
Initializing a Repository: To start a new Git repository: (If you are not cloning)
mkdir my_project
cd my_project
git init
Clone an existing repository from a remote server:
git clone https://github.com/user/repository.git
To check the status of your files in the working directory and the staging area:
git status
Adding Files Stage files for commit:
git add filename
# To add all changes:
git add .
Committing Changes
git commit -m "Commit message"
Creating a Branch
git branch new-branch
Switch to a different branch:
git checkout new-branch
Merge a branch into your current branch:
git checkout main git merge new-branch
Delete a branch:
git branch -d new-branch
- Working with Remote Repositories
Add a remote repository:
git remote add origin https://github.com/user/repository.git
Fetch changes from a remote repository:
git fetch origin
Push changes to a remote repository:
git push origin main
Pull changes from a remote repository and merge them into the current branch:
git pull origin main
- Advanced Git Features
Save your uncommitted changes to a stash:
git stash
Apply stashed changes:
git stash apply
View the commit history:
git log
Revert a commit:
git revert commit_hash
git reset is used to reset the current HEAD to a specific state, which can be a commit, a branch, or a specific file.
Modes Soft Moves HEAD to the specified commit, keeping changes in the staging area. Mixed Moves HEAD to the specified commit, unstaging changes (moves them to working directory). Hard Moves HEAD to the specified commit and discards all changes (working directory and staging area).
Syntax
git reset --soft <commit>: Moves HEAD to <commit>, keeps changes in staging area.git reset --mixed <commit>orgit reset <commit>(default): Moves HEAD to <commit>, unstages changes.git reset --hard <commit>: Moves HEAD to <commit>, discards all changes.
Use Cases Undoing Commits Resetting to a previous commit to undo changes. Unstaging Changes Removing changes from the staging area but keeping them in the working directory. Discarding Changes Completely discarding changes in both staging area and working directory.
Caution
Data Loss Using git reset --hard can lead to data loss as it discards changes irreversibly.
Use with Care Ensure you understand the consequences of resetting, especially with --hard.
Best Practices
Commit First Commit any important changes before resetting.
Review Changes Review changes carefully before performing a reset.
Backup Consider creating backups or using git reflog to recover lost commits if needed.
git log
This command displays a detailed history of commits, including commit hashes, authors, dates, and commit messages. You can navigate through the commit history using arrow keys or press q to exit the log view.
Additionally, you can use various options with git log to customize the output:
git log --oneline: Show condensed commit information on a single line.git log --stat: shows each commit along with the number of files changed, added and deleted, and a summary of the changes.git log --graph: Display commits as a graph, showing branching and merging history.git log --author="John Doe": Filter commits by author.git log --since="3 days ago": Show commits since a specific date or time.
Exploring these options can provide deeper insights into your project's commit history.
- Collaboration Workflows
Fork a repository on GitHub (use the GitHub UI for this) and then clone your fork:
git clone https://github.com/your-username/repository.git
-
Push your branch to your GitHub fork.
git push origin new-branch
-
Navigate to the original repository on GitHub.
-
Click on "Compare & pull request".
-
Provide a title and description for your pull request, then click "Create pull request".
- Git Aliases Create shortcuts for Git commands to improve efficiency:
git config --global alias.co checkout git config --global alias.br branch git config --global alias.ci commit git config --global alias.st status
- Git Hooks
Git hooks are scripts that run automatically on certain events. They are stored in the
.git/hooksdirectory of your repository.
Create a pre-commit hook to check for code formatting:
nano .git/hooks/pre-commit
Add the following script:
#!/bin/bash
if ! ./scripts/check_format.sh; then echo "Code is not properly formatted!" exit 1 fi
Make it executable:
chmod +x .git/hooks/pre-commit
I covered a wide range of Git features in the tutorial, but there are a few additional topics that I didn't mention. Here they are:
- Git Tags
Create lightweight tags to mark specific commits:
git tag tag_name
Create annotated tags with a message:
git tag -a tag_name -m "Tag message"
Push tags to a remote repository:
git push origin tag_name
git push origin --tags
Delete a tag:
git tag -d tag_name
git push origin --delete tag_name
- Git Submodules
Add a submodule to your repository:
git submodule add https://github.com/user/repository.git path/to/submodule
Update submodules to the latest commit:
git submodule update --remote
- Git Ignore
Create a
.gitignorefile to specify files and directories Git should ignore:
nano .gitignore
Add patterns for files or directories to ignore:
*.pyc
*.log
venv/
- Git Worktrees Work with multiple branches simultaneously using Git worktrees:
git worktree add path/to/branch_name branch_name
You're right; I should have included git reflog in the previous tutorial to provide a comprehensive guide on how to revert HEAD to its previous state after using git checkout HEAD^. Here's the updated information:
Reverting HEAD to the Previous State
-
Find the Previous Commit Hash Using
git reflog: First, usegit reflogto find out the commit hash thatHEADwas pointing to before you checked out the parent commit:git reflog
Look for the entry corresponding to the previous
HEADposition (usually marked asHEAD@{1}or a similar notation).
-
Checkout the Previous Commit: Once you have the commit hash from the reflog, checkout that specific commit to revert
HEADback to its previous state:git checkout
Replace <previous-commit-hash> with the actual commit hash you found in the reflog.
Example:
Let's say the reflog shows the previous HEAD position as HEAD@{1} with a corresponding commit hash of abc123.
You would revert back to the previous state with:
git checkout abc123
After running this command, HEAD will be pointing back to the commit it was at before you checked out the parent commit using git checkout HEAD^.
Using git reflog is a powerful way to track and recover previous states of HEAD or any other references in your Git history.
This creates a separate working directory for the specified branch, allowing you to work on different branches concurrently.
These additional topics cover more advanced Git functionalities that can enhance your version control workflows on Ubuntu.
********* Checkout ****************************
git checkout is a versatile command in Git that serves multiple purposes:
Switching Branches: You can use git checkout to switch between different branches in your repository. For example:
git checkout main
This command switches to the main branch.
Checking Out Commits: You can also use git checkout to move HEAD to a specific commit, either by referencing its commit hash directly or using relative references like HEAD^, HEAD~2, etc. For example:
bash
git checkout abc123 # Check out the commit with hash abc123 git checkout HEAD^ # Move HEAD to the parent commit
Detaching HEAD: When you check out a commit directly (not a branch or tag), HEAD becomes "detached" from any branch. This means that any new commits made in this state won't belong to any branch until you create a new branch or switch back to an existing branch.
Checking Out Tags: Similarly, you can use git checkout to check out a specific tag:
bash
git checkout v1.0.0 # Check out the tag named v1.0.0
Overall, git checkout is a fundamental command in Git for navigating and manipulating the state of HEAD within your repository, whether it's for switching branches, examining historical commits, or working with tags.
im in detach mode, what should i do now
When you're in a "detached HEAD" state in Git, it means that HEAD is pointing directly to a commit, rather than to a branch reference. This state is common when you use git checkout to move to a specific commit hash or tag.
Here's what you can do while in a detached HEAD state:
-
Create a New Branch: If you want to continue working on changes from this point, it's recommended to create a new branch from the detached commit:
git checkout -b new-branch-name
Replace
new-branch-namewith the name you want to give to your new branch. This action will create a new branch starting from the current commit and switch to it, allowing you to make new commits that are part of this branch. -
Reattach to an Existing Branch: If you intended to be on an existing branch but accidentally ended up in a detached HEAD state, you can reattach
HEADto the branch:git checkout existing-branch-name
Replace
existing-branch-namewith the name of the branch you want to switch to. -
Inspect or Cherry-Pick Commits: While in a detached HEAD state, you can also inspect the commit, review changes, or even cherry-pick commits to apply them elsewhere in your repository:
git show # View details of the detached commit git cherry-pick # Apply the changes from the detached commit to the current branch
-
Merge Changes: If you made changes in the detached state and want to incorporate them into a branch, you can merge the changes into a branch after reattaching
HEADto that branch:git checkout existing-branch-name # Reattach HEAD to the existing branch git merge HEAD # Merge the changes from the detached state into the current branch
Choose the appropriate action based on whether you want to continue working on a new branch, reattach to an existing branch, inspect or apply changes, or merge changes into a branch.
Error: fatal: refusing to merge unrelated histories
typically occurs when Git detects that the history of the repository you're trying to pull from does not match the history of your local repository. This often happens when the local repository was initialized separately from the remote repository, and the two histories don't share a common ancestor.
Fetch the changes from the remote repository:
git fetch origin main
Merge the fetched changes, allowing unrelated histories:
git merge origin/main --allow-unrelated-histories