Git as VCM - bounswe/bounswe2025group5 GitHub Wiki
Git is a distributed version control system designed for speed, efficiency, and seamless collaboration. It allows multiple developers to work on a project simultaneously, tracking changes and merging contributions without conflicts.
Before Git, developers relied on centralized version control systems (CVCS) like Subversion (SVN) and CVS. These systems depended on a single central server, meaning:
- 🛑 A server failure could halt all development.
- 🌐 Developers needed an internet connection to access version history.
- 📏 Scaling was difficult for large projects.
In 2005, Linus Torvalds, the creator of Linux, developed Git to overcome these limitations. Unlike CVCS, Git is:
✔ Distributed – Every developer has a complete copy of the repository, enabling offline work.
⚡ Fast & Scalable – Optimized for large projects with efficient branching and merging.
🔒 Secure – Uses SHA-1 hashing to ensure data integrity.
Since its release, Git has become the industry standard for version control, powering platforms like GitHub, GitLab, and Bitbucket. Its flexibility extends beyond software development, now widely used in research, content management, and data science.
💡 Whether you're working solo or collaborating in a team, Git provides a reliable and powerful way to track changes, experiment freely, and manage code efficiently.
Git is a distributed version control system that helps track changes in source code and collaborate with others. Here are the key concepts:
A repository is a storage space where your project’s files and their revision history are kept. It can be local (on your machine) or remote (on platforms like GitHub, GitLab).
It's a snapshot of changes in the repository. Each commit has a unique ID (SHA) and a message describing the changes.
Each brach is a separate line of development. The default branch is usually main or master. Allows working on new features without affecting the main codebase.
Combines changes from different branches into one. Can be a fast-forward (simple move) or merge commit (new commit combining histories).
These are two functions of git that enables developers to transfer files from remote to local and vice versa.
- git pull: Fetches and integrates changes from a remote repository to your local repo.
- git push: Sends your committed changes to a remote repository.
These two functions of the git allow developers to copy some other repo and store it either localy or remotely.
- git clone: Creates a copy of a remote repository on your local machine.
- Fork: Creates a personal copy of someone else’s repo on a hosting platform like GitHub. Note that this isn't a git command and cannot be used from the terminal.
A temporary space where changes are prepared before committing.
- git add: moves files to the staging area.
The local directory where you make changes to files. Untracked, modified, or staged files exist here before committing.
A version of your repository stored on a server (e.g., GitHub, GitLab, Bitbucket). Used for collaboration and backup.
- git rebase: Moves or integrates commits onto another branch, rewriting commit history.
- git cherry-pick: Applies a specific commit from one branch to another.
- git checkout: Switches between branches or restores files.
- git reset: Undoes changes, moving the branch pointer back in history.
Used to mark important commits (e.g., release versions).
- git tag v1.0 creates a tag named v1.0
Branching is a fundamental and essential feature in Git that allows you to create independent lines of development within your repository. It allows you to split off from the main line of development and work on changes separately without affecting the original codebase.
Most modern version control systems (VCS) support branching, but in Git, branching is often called the “killer feature” because it’s incredibly fast, lightweight, and central to Git’s power. This efficiency stems from how Git primarily stores data as snapshots rather than differences—meaning that a branch in Git is simply a lightweight, movable pointer to one of these snapshots (commits). It enables you to work on new features, bug fixes, or experiments without affecting the main project, while retaining a clean, stable main branch.
- Isolate changes: Keep different changes separate until they are ready to be merged.
- Facilitate collaboration: Team members can work on different features simultaneously.
- Prevent conflicts: Reduces the risk of breaking the main branch while developing new features.
- Experiment safely: Test new ideas without impacting the stable codebase.
To create a new branch, use the following command:
git branch <branch-name>
This creates a branch locally, but it won’t switch to it automatically. To switch to the new branch, use:
git checkout <branch-name>
Alternatively, you can create and switch to a new branch in one step:
git checkout -b <branch-name>
After making changes in your branch, push it to GitHub using:
git push -u origin <branch-name>
This makes the branch available for others to collaborate on.
Once your feature or fix is complete, merge it into the main branch:
git checkout main
git merge <branch-name>
To delete the branch locally after merging:
git branch -d <branch-name>
To delete the branch remotely:
git push origin --delete <branch-name>
In GitHub, it’s recommended to use Pull Requests (PRs) to merge branches. This allows for code review and discussion before merging. To create a pull request:
- Push your branch to GitHub.
- Navigate to the repository on GitHub.
- Click on Pull Requests and then New pull request.
- Select the base branch (e.g.,
main
) and the compare branch (your feature branch). - Add a title and description, then click Create pull request.
Choose the strategy that best fits your team’s workflow to promote smoother collaboration and more efficient development.
- Git Flow: Utilizes separate branches for features, releases, and hotfixes.
- GitHub Flow: Emphasizes a streamlined workflow with short-lived feature branches and frequent pull requests.
- Trunk-Based Development: Encourages continuous integration into the main branch with minimal long-lived branches.
-
Use descriptive branch names (e.g.,
feature/user-authentication
,fix/login-bug
). - Commit frequently to keep track of changes.
-
Sync your branch with the main branch regularly (
git pull origin main
). - Use pull requests for code reviews and better collaboration.
- Delete merged branches to keep the repository clean.
- Adopt a branching strategy that aligns with your team's workflow to streamline development.
By following these practices, you can maintain a well-structured and organized repository while efficiently managing your development workflow.
ℹ️ Sources: 3
Merging in Git is a method used to combine changes from different branches into a single branch. It typically involves integrating changes from a feature branch into the main branch (e.g., main
or develop
).
When you perform a merge, Git creates a merge commit, which ties together the histories of both branches. The newly created merge commit has two parent commits, the commit of the current branch and the commit from the branch being merged. This allows you to preserve the changes from both branches, maintaining a clear distinction between different lines of development.
To merge current branch, say "feature", into a stable branch, say "main", use the following command, while in branch "feature":
-
git merge main
This action will result in the following branch history:
-
* Merge commit |\ | * Commit Feature-N | * ... | * Commit Feature-M |/ * Commit Main-M * ...
Note that merge commit has two parent commits, therefore creating a nonlinear branch history.
A merge stops if there’s a conflict that cannot be resolved automatically or if the --no-commit
option was provided when initiating the merge. At this point, you can:
-
git merge --abort git merge --continue
git merge --abort will abort the merge process and try to reconstruct the pre-merge state. However, if there were uncommitted changes when the merge started (and especially if those changes were further modified after the merge was started), git merge --abort will in some cases be unable to reconstruct the original (pre-merge) changes.
- --no-ff: Ensures a merge commit is created even if a fast-forward merge is possible. (A fast-forward merge in Git occurs when the branch being merged is strictly ahead of the current branch, meaning no new commits have been made on the target branch since branching point. In this case, a merge commit is not created.)
- --ff-only: Only allows fast-forward merges, fails otherwise.
- --no-commit: Merges the changes but does not create an automatic commit.
- -X theirs / -X ours: Specifies how to resolve merge conflicts automatically. "-X theirs" prefers the incoming branch's changes, vice versa.
Rebasing is an alternative to merging that rewrites the commit history by applying changes from one branch on top of another. Instead of merging two branches and preserving their history, rebasing takes the changes from the source branch and replays them onto the target branch as if they were developed there. This results in a cleaner, linear history without extra merge commits.
While rebasing makes the commit history more readable, it can be dangerous when working with shared branches, as it rewrites commit hashes and can cause issues if not handled properly. To avoid conflicts, developers often use interactive rebase
(git rebase -i
) to edit, squash, or reorder commits before applying them.
To rebase current branch, say "feature", into a stable branch, say "main", use the following command, while in branch "feature":
-
git rebase main
This action will result in the following branch history:
-
* Commit Feature-N * ... * Commit Feature-M * Commit Main-M * ...
- --interactive: Explained above.
- --rebase-merges: Retains merge commits instead of flattening history.
- --continue, abort, skip
Merging is generally preferred for preserving a complete history of development, especially in collaborative projects where multiple developers contribute simultaneously. It ensures that every branch’s work is recorded as it originally happened. Rebasing, on the other hand, is useful for maintaining a clean history, particularly in personal or feature branches before merging into the main branch. A common workflow is to rebase a feature branch onto the latest version of the main branch (git rebase main
) before merging it back, ensuring a clean history while avoiding unnecessary merge commits.
Commits can be combined into a single commits by squashing. Squashing can be done as part of a merge or rebase operation (--squash flag), in which case it's often called a squash-merge or a squash-rebase.
- Cleaner commit history: Instead of having multiple small commits (e.g., typo fixes, debug prints), you can consolidate them into meaningful commits.
- Simplifies rollback: A single, well-structured commit is easier to revert if needed.
ℹ️ Sources: 4
The commands listed below form the backbone of everyday Git operations and are essential for both beginners and experienced
-
git init
Initializes a new Git repository in the current directory. -
git clone [repository URL]
Creates a local copy of a remote repository.
-
git status
Displays the state of the working directory and staging area, showing which changes are staged, unstaged, or untracked. Important before making any changes in both to remote and the local repositories. -
git add [file]
Adds changes in the specified file(s) to the staging area. Usegit add .
to stage all changes. Essentially, it tells Git which changes you want to include in your next commit. Before making any specific commits, the changes should be added. -
git commit -m "commit message"
Records the staged changes in the repository with a descriptive message. After the files have been added before pushing the changes you should commit your changes and add a descriptive message so other developers can understand the commit's content.
-
git branch
Lists all local branches. Also used to create a new branch (e.g.,git branch feature-branch
). -
git checkout [branch name or commit]
Switches to a specified branch or commit. Can also be used to restore files from a commit. -
git merge [branch name]
Merges changes from the specified branch into the current branch.
-
git remote
Lists remote connections, useful for managing remote repository references. It is always a good practice to check which remote connection you are working on before adding, committing, pushing or pulling anything. -
git pull
Fetches changes from the remote repository and automatically merges them into the current branch. If something has been changed in the remote repository, in order with the new version of the repository you should pull the changes. -
git push
Sends local commits to a remote repository, updating it with your changes. This will apply the committed changes in your local repository to the remote repository.
-
git log
Displays the commit history for the repository, making it easy to track changes and review commit messages. -
git diff
Shows the differences between various commits, the staging area, and the working directory.
-
git stash
Temporarily saves changes that are not yet ready to be committed. This is especially useful when you need to switch branches or work on a different task without committing incomplete changes. -
git stash pop
Applies the most recent stashed changes and removes them from the stash list.
-
git reset [commit]
Resets the current branch to a specified commit. Use with caution, as it can alter history. -
git revert [commit]
Creates a new commit that undoes changes made in a specified commit. -
git rebase [branch]
Moves or combines commits to a new base commit, streamlining a series of commits.
Git tag is a reference that points to a specific commit in your repository’s history. It’s commonly used to mark important milestones, like release points, so you can easily identify and refer back to those versions later.
-
git tag
Lists all tags in the repository. -
git tag [tag name]
Creates a new tag at the current commit (or specified commit if provided).
-
git fetch
Downloads objects and refs from another repository without merging them, allowing you to review changes before integrating. -
git cherry-pick [commit]
Applies the changes introduced by an existing commit on the current branch. -
git blame [file]
Shows what revision and author last modified each line of a file, useful for identifying the origin of a change. -
git show [commit]
Displays details about a specific commit, including the diff of changes. -
git rm [file]
Removes a file from the working directory and stages the removal for commit. -
git mv [old file] [new file]
Moves or renames a file, staging the change for commit. -
git bisect
Helps identify the commit that introduced a bug by using a binary search algorithm.
Following best practices in Git helps maintain a clean, organized, and efficient development workflow while preventing issues like merge conflicts, lost work, or confusing commit histories. Here are some key recommendations:
- Commit frequently – Small, incremental commits make it easier to track changes and roll back when necessary.
-
Write clear commit messages – Use descriptive, concise messages that explain the purpose of the change (e.g.,
fix: resolve login bug
instead offixed stuff
). Follow a consistent convention like Conventional Commits. -
Stage related changes together – Use
git add -p
to select specific changes instead of committing everything at once. -
Avoid committing sensitive data – Use a
.gitignore
file to prevent unwanted files (e.g., API keys, config files, logs) from being tracked.
- Follow a branching strategy – Choose a model like Git Flow, GitHub Flow, or Trunk-Based Development to keep branches structured.
-
Use descriptive branch names – Name branches based on purpose (e.g.,
feature/user-auth
,bugfix/login-error
,hotfix/critical-patch
). - Keep branches short-lived – Regularly merge or delete feature branches once work is complete.
-
Rebase before merging – Use
git rebase main
to update your branch with the latest changes from the main branch and reduce unnecessary merge commits.
-
Pull before pushing – Always run
git pull --rebase
before pushing to avoid conflicts. - Use pull requests (PRs) – Discuss changes before merging, ensuring quality and catching potential issues early.
- Resolve conflicts promptly – Keep your branch up to date with the main branch and resolve merge conflicts as soon as they arise.
-
Avoid force pushes (
git push --force
) – This can overwrite work done by others; usegit push --force-with-lease
to prevent accidental data loss.
-
Clean up old branches – Regularly delete merged branches (
git branch -d <branch>
andgit push origin --delete <branch>
) to keep the repository tidy. -
Use tags for releases – Tag stable versions of your project (e.g.,
git tag v1.0.0
) for easier tracking. -
Optimize repository size – Use
git gc
to clean up unnecessary files and references, and avoid committing large files (use Git LFS if needed). -
Keep commit history clean – Use interactive rebase (
git rebase -i
) to squash unnecessary commits before merging.
By following these best practices, you can ensure a structured, efficient, and scalable Git workflow that enhances team collaboration and code quality.