4 Use Git and GitHub
I assume you already have an account on https://github.com. If not, you need to create an account there.
4.1 Download Git
Go to the website https://git-scm.com/downloads, select an appropriate operating system, select “Click here to download”
Run the downloaded setup file with a name such as
Git-2.42.0.2-64-bit.exe
, and accept all default options.
4.2 Establish a connection between a local repo and a remote GitHub repo
4.2.1 Clone an existing repo on GitHub
This is an easier way to establish a connection between a local repo and a remote repo if the remote repo is created ahead. We will make a connection between a remote repo in your GitHub account and a local directory. If the remote repo is not under your account, then skip steps 1 and 2.
Sign in to your GitHub account, and create a GitHub repo (such as named
homework
) onGitHub
(https://github.com), you can add a README.md file or just choose not to add a README.md file.On your local computer, open a
Git Bash
terminal.Skip this step if you simply want the cloned repo to be in the current directory. Otherwise, In the terminal, type
mkdir myfolder
(create a folder namedmyfolder
within the current directory) and thencd myfolder
(change to the directorymyfolder
). The directory namemyfolder
can be any name you want.git clone https://github.com/Your_Git_UserName/homework.git
(change the remote repo path to match your actual remote repo).NoteTo specify a specific folder to clone to, add the name of the folder after the repository
URL
, like this:git clone github-repo-URL mylocalfolder
Now you have established a connection between your local directory
homework
and the remote repohomework
on GitHub.Create a new file in the current local directory
homewor
on your local computer, such as using your favorite editor to create a file namedmyfirstlocalfile.txt
with any content in it. Or for the sake of demonstration, you can use the following Linux command to create this file containing the line#My first local file
.echo "#My first local file" >> myfirstlocalfile.txt
In the terminal,
git add .
This will add all changes to the staging area. This lets Git start to track the changes to files in your local directory.Now you are ready to commit the changes, which versions (takes a snapshot of) the current files in the directory. A commit is a checkpoint where you can go back to.
git commit -m "my first commit from local"
Now you are ready to sync the local repo with the remote repo.
git push
The GitHub might ask you to sign in for the first time. Choose
Sign in with your brower
to sign in to complete the push.
4.2.2 Initializing a Git Directory Locally First
The previous approach initializes a local Git repo by cloning a remote repo. You can also initialize a local Git repo by using git init
. Follow the following steps:
Sign in to your GitHub account.
Create a GitHub empty repo (such as named
homework
) onGitHub
(https://github.com) but make sure it is empty (do not add Readme.md file)Start a Git Bash Terminal window on your local computer (You could also use the Terminal Window in RStudio or VSC). Navigate to the project directory; if you haven’t yet created a project directory such as
homework
, domkdir project_dir
Example:mkdir homework
Use
cd project_directory_name
to enter your local project directory;Use
ls
to list all files and directories or usels -al
to include all hidden files and directories. In your local Git Terminal, (note at this moment your local project directory is empty)echo "# homework0" >> README.md #create a file README.md git init git branch -M main #rename the branch name to main git add . # may use git add --all git commit -m "first commit" git remote add origin https://github.com/ywanglab/homework.git #(change the remote repo path to your remote repo) git push -u origin main # only need to do this first time. Afterwards, only `git push`
Notethe general command format:
git push [remote-name] [branch-name]
difference between
git add .
andgit add --all
:git add .
: stages changes in the current directory and its subdirectories but does not include file deletionsgit add --all
: stages changes in the entire working tree, including deletions and untracked files. It is a more aggressive option and can be useful when you want to ensure that every change, including file deletions, is included in the next commit.git add --all
is equivalent togit add -A
if your local project directory already 1) contains files and 2) had performed
init git
before, thengit remote add origin https://github.com/ywanglab/homework.git` #(change the remote repo path to your remote repo path) git branch -M main git push -u origin main
in the pop-out
GitHub Sign-in
window, click onSign in with your browser
.Note an empty folder would not be pushed to the remote repo until it has a file (even an empty file) in it. In this case, you can create an empty file such as
.gitignore
4.3 Some other common commands
check git status:
git status
andgit status --short
for a compact way.git commit -a -m "message"
will stage and commit every changed, already tracked file without usinggit add changed_file
git add file_changed
# add
file_changed
to the staging environment, i.e., git repo to start track those changes.use
git log
to check all commits. Usegit log --pretty=oneline
or justgit log --oneline
for shorter display.git log origin/main
#check the remote repoorigin/main
commitsuse
git diff origin/main
to show the differences between the localmain
andorigin/main
.use
git checkout .
to revert back to the previous commit. Any changes after the previous commit will be abandoned.to get to a previous commit, use
git checkout seven_character_commit_hash
. To get back to main, usegit checkout main
.Git commit --amend
commit --amend
is used to modify the most recent commit
. It combines changes in the staging environment
with the latest commit
, and creates a new commit
. This new commit
replaces the latest commit
entirely. Adding files with--amend
works the same way as above. Just add them to the staging environment
before committing.
One of the simplest things you can do with --amend
is to change a commit
message with spelling errors.
Git Revert HEAD:
revert
is the command we use when we want to take a previous commit and add it as a new commit, keeping the log intact. Revert the latestcommit
using gitrevert HEAD
(revert
the latest change, and thencommit
), adding the option--no-edit
to skip the commit message editor (getting the defaultrevert
message):git revert HEAD --no-edit
NoteTo revert to earlier commits, use
git revert HEAD~x
(x
being a number. 1 going back one more, 2 going back two more, etc.)Git Reset
reset
is the command used when we want to move the repository back to a previouscommit
, discarding any changes made after thatcommit
. Let’s try and do that with reset.git reset seven-char-commit-hash
Git Undo Reset
Even though the commits are no longer showing up in the log, it is not removed from Git. If you know the commit hash you can reset to it:
git reset seven-char-commit-hash
To permanently go back to a previous commit, use
git reset --hard seven_char_commit_hash
to go back to a previous commit, but not changing the files in the working directory use the
--soft
` option.git reset --soft seven_char_commit_hash
git remote -v
Get the reminder of the remote repo. To rename the remote origin:git remote rename origin upsteam
rename remote repoorigin
toupstream
NoteAccording to Git naming conventions, it is recommended to name your own repository
origin
which you have read and write access; and the one you forked forupstream
(which you only have read-only access.)if you want to remove the file only from the remote GitHub repository and not remove it from your local filesystem, use:
git rm -rf --cached file1.txt #This will only remote files; If intending to remove local files too, remove --cached
git commit -m "remove file1.txt"
And then push changes to remote repo
git push origin main
- For some operating system, such as Mac or Linux, you might be asked to tell GitHub who you are. When you are prompted, type the following two commands in your terminal window:
git config --global user.name "Your Name"
git config --global user.mail "your@email.com"
This will change the Git configuration in a way that anytime you use Git, it will know this information. Note that you need to use the email account that you used to open your GitHub account. global
sets the username and e-mail for every repo on your computer. If you want to set the username/e-mail just for the current repo, remove global
.
4.4 Use Git help
git command -help
See all the available options for the specific command. Use `--help
instead of-help
to open the relevant Git manual page.git help --all
See all possible commands
4.5 When the upstream repo changes
When Git tells you the upstream repo is ahead,
Do
git pull
orgit pull origin
This is equivalent to
git fetch origin
, and thengit merge origin/main.
Then you can commit and push a new version to the remote repo.git pull
will not pull a new branches on the remote repo to local, but it will inform you if there is a new branch on the remote repo. In this case, justgit checkout the_remote_new_branch_name
will pull the remote branch to local. Note there is no need to create locally the branch bygit branch the_remote_new_branch_name
4.6 Create branch
To add a branch to the main branch
git branch branchname
Switch the branch
git checkout branchname
To combine the above two actions,
git checkout -b branchname
, create a new branch namedbranchname
if it does not exist and move to it.
Adding a file in branch echo "#content" >> filename.txt
Then add
the file and commit the file. To push the branch to the remote repo we have to use
git push --set-upstream origin branchname
The option --set-upstream
can be replaced by -u
to see all branches in both local and remote: git branch -a
Or git branch -r
for remote only.
4.7 Merge branch to main branch
Switch from a branch (with name such as
branchname
to themain
using
git checkout main
on the
main
branch, Merge command to merge the branches
git merge branchname
To delete a branch:
git branch -d branchname
4.8 Handle large files (>= 150Mb) on GitHub
GitHub does not allow to upload a file of size greater than 150Mb. However, one can use git lfs
to handle large files exceeding this size up to several Giga bytes. The first thing is to install git lfs
. Head to https://git-lfs.com, once dowlonad and install the Git command line extension, set up Git LFS for your user account by running
git lfs install #(only need to do this the first time)
Then In each Git repository where you want to use Git LFS, select the file types you’d like Git LFS to manage (or directly edit your .gitattributes). You can configure additional file extensions at any time.
git lfs track "path/to/file"
Then do the regular git add .
and git -m "message"
and git push
. Note one must use git lfs track
a file first before doing git add
and git commit
.
Note you need to track the large-size file first before you add it to the staging area. But often you will find this error after you try to push your changes to the GitHub. In this case, you will have to remove the commit history of this file first. One way to do this is to reset –soft
the HEAD to the previous working HEAD, and then do git lfs track
followed by git add
and git commit
, git push
. Specifically,
git reset --soft HEAD ~1 # or the_7-char_commit_hash
git lfs track "path/to/large_file"
git add .
git commit -m "commit message"
git push
Note the --soft
option allows the changes in the working directory not affected, otherwise any change after the previous commit will be removed.
4.9 Contribute by forking a GitHub repo and commit to the forked repo and create a pull request (refer to [the best workflow below]Section 6.3 )
after forking a (foreign) GitHub repo to your own GitHub account,
git clone
that repo under your account to your local repo.make changes in your local directory.
Submitting your changes for review
Commit your changes locally. Once you are ready to submit your changes, run these commands in your terminal:
git add -A # Stages all changes, short for --all git commit -m '[your commit message]' # Makes a git commit
Make a pull request. (A pull request is a proposal to change) A GitHub pull request allows the owner of the forked upstream repo to review and make comments on your changes you proposed. Once approved, the upstream owner can merge your changes. Run:
git push origin # Push current branch to the same branch on GitHub
Then go to your remote forked repo in your account on the GitHub site and click Contribute,and then Open pull request, this will take you to the upstream repo. In the form, leave a message explaining the change, and Create pull request. Do not select
Close pull request
unless you want to cancel the pull request.
4.10 Project
First make sure you have forked the course repo
https://github.com/ywanglab/stat1010.git
to your own GitHub account.
Now go to your GitHub account, git clone the forked course repo
git clone https://github.com/your_git_user_name/stat1010.git
to your local computer
- add your resume file in the folder
./resume
git add
, commit
and push
your changes to the upstream repo using
git add .
git commit -m "added YourFirstName's resume"
git push origin
- Then go to your remote forked repo in your account on the GitHub site and click Contribute,and then Open pull request, this will take you to the upstream repo. In the form, leave a message explaining the change, and Create pull request. Do not select
Close pull request
unless you want to cancel the pull request.
4.11 More on git
git pull
= git fetch
+ git merge
git fetch
→ downloads commits from the remote into your local refs (e.g.origin/main
).git merge
→ merges those new commits into your current branch.
4.12 Git pull: What does --ff
mean?
--ff
= fast-forward if possible.- That means: if your branch has no local commits since it last matched the remote, Git will simply move the branch pointer forward to match the remote — no merge commit is created.
Example (before pull):
A---B---C (origin/main)
A---B (main)
If you run git pull --ff
and your branch is strictly behind origin/main
, Git just slides main
forward:
A---B---C (origin/main, main)
git pull
without flags:- May create a merge commit if histories diverged.
git pull --ff
:- Does a fast-forward if possible.
- If not possible (you made local commits), Git falls back to a merge commit.
git pull --ff-only
:- Does a fast-forward only.
- If not possible, it aborts with an error (no merge commit allowed).
--ff
is safe if you don’t mind merge commits being created when necessary.--ff-only
is stricter (no merge bubbles, linear history).Teams often configure one of these globally so
git pull
always behaves consistently.
when there is a diverge
--ff-only
→ aborts with an error.--ff
→ falls back to a merge, creating a merge commit (see next section).
4.12.1 git pull
or git pull --ff
(merge fallback)
- Git fetches
origin/main
atC
- Git merges
C
into your localmain
withD
, producing M:
After pull (local):
A──B──C
\ \
D─M (main)
^
merge commit
When you run git merge origin/main
(or git pull
with merge strategy):
Git identifies the common ancestor of the two branches → here, commit B.
Then it looks at:
- The changes between
B
→C
(remote’s changes). - The changes between
B
→D
(your changes).
- The changes between
Git tries to combine both sets of changes into a new snapshot.
That new snapshot becomes a new commit M. The merge commit M exists only locally until you git push
. * When you push, origin/main
is updated to point to M, and the remote history now includes that merge commit.
- Pros: Preserves exact history as it happened (no rewrite).
- Cons: Adds merge commits; history can get “braided”.
4.12.2 Option 2: git pull --rebase
(replay your work on top of remote)
Git rewrites your local commits onto the fetched remote tip:
- Rewrites
D
intoD'
applied afterC
.
- Rewrites
A──B──C──D' (main)
^
rebased (new) commit
- Pros: Linear history, no merge commit.
- Cons: Rewrites your local commits (new SHAs). If you had already pushed
D
, you’ll needgit push --force-with-lease
, see below.
4.13 How to set opitons gloabally
Team prefers linear history →
git pull --rebase
(and set it as default)git config --global pull.rebase true git config --global rebase.autoStash true
Keep exact history / avoid rewrite →
git pull --ff
(merge when needed)git config --global pull.rebase false
Never auto-merge; be explicit →
git pull --ff-only
git config --global pull.ff only
5 Concrete example: what does “merge C with D to produce M” look like?
Assume the repo has one file, README.md
.
5.0.1 Commits and changes
B (common ancestor)
README.md
:Hello project
C (remote, on origin/main) — someone else added a line:
Hello project Remote line
D (your local commit, on main) — you added a different line:
Hello project Local line
So history diverged:
A──B──C (origin/main)
\
D (main)
5.0.2 You run: git pull
(merge strategy) or git merge origin/main
Git computes the diff B→C (“add Remote line
”) and B→D (“add Local line
”), applies both, and creates merge commit M:
M (merge result):
Hello project Local line Remote line
(order may vary if both append—Git picks a consistent merge; if both edit the same line, you’ll get a conflict to resolve.)
New history:
A──B──C
\ \
D─M (main)
M has two parents: D and C. That’s a “merge commit”.
6 3) What is git push --force-with-lease
(and why it’s safer than --force
)?
When you rebase local commits that were already pushed, your local branch history no longer matches the remote’s. A normal git push
will be rejected. You need to overwrite the remote branch tip—i.e., a force push.
git push --force
overwrites the remote branch unconditionally (dangerous—you could clobber someone else’s new commits if they pushed while you were rebasing).git push --force-with-lease
is the safe version:- It says: “Force-push only if the remote branch still points to the commit I think it does.”
- If someone else has pushed new commits, the push is rejected instead of overwriting their work.
6.0.1 Typical rebase + push flow
# Update local view of remote
git fetch
# Rebase your local work onto the remote tip
git rebase origin/main # resolve conflicts if any; git rebase --continue
# Safely update the remote branch
git push --force-with-lease
6.0.2 Example workflow with git stash
6.0.2.1 1. Check repo status
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: app.py
modified: utils.py
You’ve made some edits but don’t want to commit yet.
6.0.2.2 2. Stash your changes
$ git stash push -m "WIP: refactor utils"
Saved working directory and index state WIP on main: 1a2b3c4 Add logging
Now the working directory is clean.
6.0.2.3 3. Verify with status
$ git status
On branch main
nothing to commit, working tree clean
The changes are hidden away.
6.0.2.4 4. List stashes
$ git stash list
stash@{0}: On main: WIP: refactor utils
Your stash is safely stored.
6.0.2.5 5. Switch branch, pull, or do other work
$ git switch feature-branch
Switched to branch 'feature-branch'
6.0.2.6 6. Apply the stash back
$ git stash apply stash@{0}
On branch feature-branch
Changes not staged for commit:
modified: app.py
modified: utils.py
Changes are back, but the stash still exists in the list.
6.0.2.7 7. Or use pop
to apply and remove
$ git stash pop
On branch feature-branch
Changes not staged for commit:
modified: app.py
modified: utils.py
Dropped refs/stash@{0} (abc123def456...)
6.0.2.8 8. Confirm stash list is empty
$ git stash list
# (no output — list is empty)
summary
- You edited files.
git stash push
cleaned your working directory but saved changes.- Later,
git stash apply
orgit stash pop
restored those changes.
6.1 Rebuild the index respecting .gitignore
If you have modified .gitignore
and you already pushed some files that you did not want to push, to remove those files already pushed to Github, you need to remove them from the git index to untrack them.
git rm -r --cached . #redo all the index
git add .
git commit -m "Reindex: drop ignored files from repo"
git push origin <your-branch>
to remove specific folder or files:
git rm -r --cached .Rhistory .Rproj.user # `-r` is needed for a directory
6.2 Unstage and untrack
- unstage = remove from the staging area (index), but keep the file under Git’s tracking.
- untrack = stop Git from tracking the file altogether.
6.2.1 To unstage (but keep tracking):
If you already ran git add file.txt
and want to undo that:
git reset HEAD file.txt
Now file.txt
is back in “modified” state but not staged. To unstage everything:
git reset HEAD
6.2.2 To unstage:
If a file is already committed to the repo but you want Git to forget it:
git rm --cached file.txt
--cached
removes it from the index (tracking) but leaves it in your working directory.- Next commit will record the removal.
- If you want to untrack entire directories:
git rm -r --cached my_folder/
6.2.3 Prevent tracking in the future
Add the file or folder to .gitignore
so Git won’t pick it up again:
# .gitignore
file.txt
my_folder/
6.3 Best workflow with GitHub from Colab (or a local device)
Pre-req: Local repo is a clone of the GitHub repo with aligned HEAD
Keep sync with the upstream original owner repo. On GitHub, in the forked repo (under your account), Click on “Sync fork”.
Open (or create) a notebook from G-drive to work with in Colab.
Then, mount the G-drive. If on a local device, use the same workflow (open or create a notebook from the project directory).
In a termnal of Colab (or a terminal in VSC in a local device)
git pull
orgit pull --ff
or (safer method:git pull --ff-only
)
If permission denied on G-drive, run this first then repeat git pull.
chmod +x .git/hooks/*
- After editing, and before finish
git status
git add files-to-commit
git commit -m "commit message"
git push # this will push the files-to-commit to your fork/main
6.4 Team Github workflow
6.5 Initial setup
- Fork and Clone
- Fork: You click “Fork” on GitHub → it creates a copy of the repo under your GitHub account. Navigate to
https://github.com/ywanglab/STAT4160
, then click on “Fork”. - Clone: You download a local copy of your fork to your computer. (only do this for the first time)
So after forking, you typically do (only for the first time)
git clone https://github.com/YOUR-USERNAME/REPO-NAME.git #REPO-NAME should be STAT4160
cd REPO-NAME # the REPO-NAME should be STAT4160, cd to the current working directory
- Add the original repo as “upstream”
Your fork is linked to your GitHub account (the “origin”). To stay in sync with the original project, add a remote for the source repository:
git remote add upstream https://github.com/ywanglab/STAT4160
Check remotes:
git remote -v
# origin https://github.com/YOUR-USERNAME/REPO-NAME.git (push/pull)
# upstream https://github.com/ORIGINAL-OWNER/REPO-NAME.git (pull only)
- Create a feature branch in your fork
Never work directly on main
. Instead create a new branch:
git checkout -b feature/my-contribution # eg: homework/your_initial
# edit files...
# after you done your edit, push changes to origin/main
git add files-to-commit # git add filename (or directoryname) use `.` rarely as it will add all files in the git directory.
git commit -m "Fix bug in utils"
git push -u origin feature/my-contribution #git push by default push changes to origin/main
Open a Pull Request (PR) (only do this for the contribution you want to make, such as homework)
Go to your fork on GitHub (
https://github.com/YOUR-USERNAME/REPO-NAME
).GitHub will show a banner: “You recently pushed to
feature/my-contribution
. Do you want to open a Pull Request?”Click it → select base repository = (upstream) original owner repo, compare = your branch.
Note: head repository
→ your fork (e.g. YOUR-USERNAME/REPO-NAME) and branch (feature/…) that contains your changes.
- Write a good description and submit the PR.
Now the maintainers of the original repo will review it. If approved, they’ll merge it.
6.6 Keep your fork in sync
Before making new contributions, update your fork/main
with the latest main
from upstream:
Option A) Do it on GitHub: If GitHub shows something like “This branch is 1 commit behind”, “Sync Fork”.
Option B): do it via terminal:
git checkout main # checkout main
git pull upstream main # pull from the upstream original repo
git push origin main # update your fork on GitHub
Then branch off main
again for your next feature.
6.7 Git FAQ
- Explain staging area, working area, working directory
- Working directory / working tree (aka “working area”): The files on your disk you edit.
- Staging area (index): The “snapshot-in-progress” you will commit next. You move changes here with
git add
. - Local repository (
.git
): The database of commits/objects/refs.git commit
writes a new commit to this store. - HEAD: A pointer to your current commit/branch.
6.7.1 Working directory (working tree) vs “actual files on disk”? Save vs commit? What are “index” and “working tree”?
- Working directory/working files / working tree: the files on your disk under the repo. This is the “actual files on disk” for the project (both tracked and untracked). What
git status
calls “Changes not staged for commit” (for tracked edits) and “Untracked files”. - Index (staging area): a binary file at
.git/index
that holds the exact snapshot you will commit next. You put changes into the index withgit add
.Git status
calls “Changes to be cmmitted”.
Compare the layers
git status # see working tree vs index vs HEAD
git diff # working tree vs index: what you edited but haven't staged.
git diff --staged # index vs HEAD: what's staged vs. last commit
git log --oneline --graph --decorate --all # visualize history (merge vs rebase)
Flow:
(edit & save) → working tree
git add → index
git commit → new commit from the index
- Local repository: all Git objects in
.git/
(commits, trees, blobs, refs).
Save vs commit
- Save: editor/OS action that writes a file to disk (affects working tree only).
- Commit: Git action that records a snapshot of the index into the repository history (
.git/objects
) with a message and metadata.
6.7.2 1) After git add
, how to undo (un‑add) a file or directory?
Unstage (but keep your edits in the working tree):
# Preferred (Git 2.23+)
git restore --staged <file-or-dir>
# Older (still works)
git reset HEAD <file-or-dir>
# Unstage everything that’s currently staged
git restore --staged .
# or
git reset #eqiv to: git reset --mixed HEAD: reset the index to match the current HEAD (unstaging changes) but does not move HEAD
Partially unstage hunks:
git restore --staged -p <file> # or: git reset -p <file>
If you accidentally started tracking something (e.g., should be ignored), remove it from the index only:
git rm --cached -r <path> # leaves the file(s) on disk, stops tracking
6.7.3 2) After git commit
, how to un‑commit?
Undo the last commit locally (choose how much to keep):
git reset --soft HEAD~1 # keep changes staged
git reset --mixed HEAD~1 # keep changes in working tree (unstaged) [default]
git reset --hard HEAD~1 # discard the commit AND your local changes (danger!)
If the commit is already pushed (others may have pulled it), prefer:
git revert <commit-sha> # makes a new commit that undoes the old one
Fix or edit the most recent commit without changing its parent:
git commit --amend
git commit --amend
(more)
Rewrites the last commit.
Fix message only:
git commit --amend -m "Better message"
Add forgotten changes (stage them first):
git add <files> git commit --amend --no-edit # keep prior message
Change author/committer timestamp:
git commit --amend --no-edit --reset-author
Results in a new commit SHA. If the old commit was pushed, you’ll need:
git push --force-with-lease
If you must rewrite published history (e.g., after a local rebase), push safely:
git push --force-with-lease
6.7.4 3) When git push
, what conflicts can occur? How to fix them?
A “push conflict” is usually a non‑fast‑forward rejection because the remote has new commits you don’t have.
Symptom: rejected] ... (fetch first)
or non-fast-forward
.
Fix:
git fetch origin
# Option A: merge
git merge origin/<branch>
# Option B: rebase (keeps history linear)
git rebase origin/<branch>
# After Having Resolved any conflicts, then:
git push
6.7.5 4) When git pull
, what conflicts can occur, and how to fix them?
git pull
= fetch + merge
(by default) or fetch + rebase
(with --rebase
). Conflicts occur when both sides changed the same lines or one side edits a file the other deleted.
Merge flow (default pull):
git pull
# If conflicts:
git status
# open files, resolve <<<<<<< ======= >>>>>>> markers
git add <resolved-file>...
git commit # completes the merge
Rebase flow (git pull --rebase
):
git pull --rebase
# If conflicts:
git status
# resolve, then:
git add <resolved-file>...
git rebase --continue
# or:
git rebase --abort # to go back to the state right before rebase
Related:
git rebase --continue
→ after resolving a conflict, proceed to the next commit.git rebase --skip
→ drop the problematic commit and continue.git rebase --quit
→ stop the rebase without resetting your current files/HEAD; it just removes rebase state (rarely needed—--abort
is the safe “put it back” button).
Helpful:
git mergetool # launch a diff/merge tool if configured
6.7.6 5) Why create a new branch instead of working on main
?
- Keep
main
clean, stable, and deployable. - Isolate work so you can open focused pull requests and get review.
- Parallel development without stepping on each other.
- Safer experiments; easy to abandon a branch if it doesn’t pan out.
- Release/hotfix workflows (e.g.,
release/*
,hotfix/*
). - CI/policy gates per branch.
6.7.7 6) How git stash
works and why we need it
git stash
saves your uncommitted changes (working tree and staged) into a stack entry, then reverts your tree to a clean state—handy when you must switch branches or pull/rebase but aren’t ready to commit.
Common commands:
git stash push -m "wip: message" # save staged + unstaged
git stash push -u # include untracked files
git stash push -a # include ignored files
git stash list
git stash show -p stash@{0} # see what’s inside
git stash apply stash@{0} # apply, keep it on the stack
git stash pop stash@{0} # apply and remove from the stack
git stash drop stash@{0}
# Partial / path-specific:
git stash -p # interactively stash hunks
git stash push -- <path1> <path2> # stash only these paths
6.7.8 8) Difference between git reset
and git revert
git reset
: Moves a branch/HEAD to another commit (optionally touching index and working tree). It rewrites history for that branch.--soft
: move HEAD only (keep index + working tree)--mixed
(default): move HEAD + reset index (keep working tree)--hard
: move HEAD + reset index + working tree (discard changes)- Use for local surgery (e.g., uncommit/squash) before sharing.
git revert
: Creates a new commit that undoes the changes from a prior commit. Does not rewrite history; safe on shared branches.
Rule of thumb: Use revert
for public history, reset
for local/private history.
6.7.9 9) How to remove files that are already pushed? Explain git rm --cached
If you only want Git to stop tracking the file(s) but keep them on disk:
git rm --cached -r <path>
echo "<path>/" >> .gitignore
git commit -m "Stop tracking <path>"
git push
git rm --cached
removes from the index (stops tracking) but does not delete your local copy.
If sensitive/big files are already in history and must be purged:
- Use git filter-repo (recommended) or BFG:
# after installing git-filter-repo
git filter-repo --path <path> --invert-paths
git push --force-with-lease --all
git push --force-with-lease --tags
- Rotate any exposed secrets and tell collaborators to re-clone or hard‑reset to the new history.
6.7.10 10) Difference between git pull --rebase
and git pull -ff
git pull --rebase
: Fetch, then reapply your local commits on top of the updated upstream. This rewrites your local commits for a cleaner, linear history. Configure permanently:git config --global pull.rebase true # always rebase on pull # or for one repo: git config pull.rebase true
-f
is a short flag for fetch –force, so-ff
is basically “fetch with force (twice)””.
If you don’t use
--rebase
, thengit pull
merges by default.--ff-only
keeps history clean by aborting instead of making a merge commit when a fast‑forward isn’t possible.
6.7.11 11) Explain git rebase
Rebase “moves” your commits to a new base commit.
Example: keep a feature branch up to date without merge commits:
git checkout feature
git fetch origin
git rebase origin/main # replay feature’s commits on top of latest main
# resolve conflicts per-commit:
git add <resolved-file>...
git rebase --continue
# when done and if previously pushed:
git push --force-with-lease
Interactive rebase to clean history (reorder/squash/edit/drop):
git rebase -i HEAD~5
# pick | reword | squash | fixup | edit | drop
# tip: use autosquash:
git commit --fixup <sha>
git rebase -i --autosquash origin/main
Advanced: move a range of commits to a different base:
git rebase --onto <new-base> <old-base> <branch>
Guidelines
- Don’t rebase commits others are already depending on (unless your team agrees and you use
--force-with-lease
). - Test after rebases; conflicts are resolved commit‑by‑commit.
6.8 4) Difference between git rebase
and git merge
Goal (both): bring changes from one line of history into another.
6.8.1 Merge
- Creates a merge commit that has two parents; preserves true history.
- Doesn’t rewrite existing commits.
- Safer on shared branches; good for “what actually happened.”
# Before
main: A---B---C
\
feature: D---E
# Merge feature -> main
main: A---B---C---M
/ \
feature: D-----E
6.8.2 Rebase
- Rewrites your commits to appear on top of a new base (new SHAs).
- Produces a linear history (no merge commit).
- Avoid rebasing commits others already pulled (or force-push with care).
# Rebase feature onto latest main
main: A---B---C
\
feature: D'--E' (D and E replayed; new SHAs)
Rule of thumb: merge for public/shared history; rebase to keep your feature branch tidy before sharing.
6.8.3 On which branch do merge
and rebase
happen?
git merge other-branch
merges other-branch into the branch you currently have checked out (the “current branch”). If you want to merge into some target branch, you must first switch to it:git switch target git merge other
git rebase <upstream>
rewrites the current branch so its commits replay on top of<upstream>
:git switch feature git rebase origin/main
Advanced: you can rebase a branch without checking it out:
git rebase origin/main feature # rewrites 'feature'
But conceptually, rebase always moves one branch’s commits onto a new base.
6.9 Quick reference (handy snippets)
# Unstage everything
git restore --staged .
# Uncommit but keep edits
git reset --mixed HEAD~1
# Undo a pushed commit safely
git revert <sha>
# Resolve pull with rebase and conflicts
git pull --rebase
# ...resolve...
git rebase --continue
# Stop tracking a file/folder (keep it locally)
git rm --cached -r <path> && echo "<path>/" >> .gitignore
# Fast‑forward only pull (abort if divergence)
git pull --ff-only
6.10 1) Index vs. working files (aka working tree)
Working files / working tree
- The actual files on disk that you edit and save in your editor.
- Can include both tracked and untracked files.
- What
git status
calls “Changes not staged for commit” (for tracked edits) and “Untracked files”.
Index / staging area
- A snapshot Git keeps (in
.git/index
) of exactly what will be committed next. - You put changes into the index with
git add
. - What
git status
calls “Changes to be committed”.
Compare the layers
git diff # working tree vs index (what you edited but haven't staged)
git diff --staged # index vs HEAD (what's staged vs last commit)
Flow:
(edit & save) → working tree
git add → index
git commit → new commit from the index
6.11 3) “I saved a file on one branch, then checked out a new branch and edited it again. What version do I have on disk?”
It depends on whether your first edits were committed and whether switching branches would overwrite those edits.
6.11.1 Cases
You did NOT commit, and the switch would overwrite your changes Git blocks the switch:
error: Your local changes to the following files would be overwritten by checkout: path/to/file
Fix: commit, stash, or discard those changes first.
You did NOT commit, and the switch does NOT overwrite your changes Git allows the switch and carries your uncommitted edits into the new branch. On disk you see your latest saved content (not the branch’s clean version). The changes now show as “modified” on the new branch. If you commit now, the commit lands on the new branch.
You DID commit on the first branch When you switch, Git rewrites your working tree to match the target branch’s snapshot. You’ll see the target branch’s version of the file on disk.
Untracked files Untracked files follow you across branches. If an untracked path would conflict with a tracked file in the target branch, Git blocks the switch unless you stash with
-u
or clean withgit clean -fd
(dangerous).
6.11.2 Tips
To keep branch changes separate, either commit/stash before switching or use separate work trees:
git worktree add ../repo-main main git worktree add ../repo-feature feature
To forcibly see a file as it exists on another branch (without switching):
git show other-branch:path/to/file > path/to/file # overwrites file on disk # or, with restore (safer semantics): git restore --source other-branch -- path/to/file
6.12 4) Suggested team workflow (you maintain main
, teammates contribute)
Below is a light‑weight, reliable feature‑branch + PR flow (GitHub/GitLab/Bitbucket compatible).
6.12.1 Repository / policy (one‑time setup)
- Protect
main
: disallow direct pushes, require PRs, require at least 1 review, require CI to pass, and (optionally) Require linear history. - Prefer “Squash and merge” or “Rebase and merge” on PRs to keep
main
tidy. - Add CODEOWNERS (optional) so certain paths require your review.
- Encourage small, focused PRs.
6.12.2 Personal Git config (everyone)
git config --global pull.rebase true # rebase on pull; cleaner history
git config --global fetch.prune true # remove deleted remote branches on fetch
git config --global rerere.enabled true # remember conflict resolutions (handy)
6.12.3 Contributor workflow (feature branch)
# 1) Sync and branch off up-to-date main
git switch main
git fetch origin
git pull --ff-only # keep local main as a clean fast-forward
git switch -c feature/short-desc
# 2) Develop
# ...edit, test, commit in small logical chunks...
git add -p
git commit -m "feat: short message"
# 3) Keep branch current (periodically)
git fetch origin
git rebase origin/main # replay your commits on latest main
# resolve conflicts → git add ... → git rebase --continue
# 4) Publish and open PR
git push -u origin feature/short-desc
# (Open PR, link issue, ensure CI passes, request review)
# 5) Address review
# Use fixup commits for clean history:
git commit --fixup <sha-to-fix>
git rebase -i --autosquash origin/main
git push --force-with-lease
6.12.4 Maintainer (you) merging PRs
Ensure tests pass, reviews done.
Choose Squash & Merge (one clean commit on
main
) or Rebase & Merge (preserve individual commits but linear).After merge:
# Keep your local main clean and current git switch main git pull --ff-only
Optionally tag releases:
git tag -a v1.2.3 -m "Release 1.2.3" git push origin v1.2.3
6.12.5 Hotfixes
- Branch from
main
:git switch -c hotfix/issue-123
- Patch, test, PR, merge → tag a patch release.
6.12.6 Common “gotchas” and fixes
- Push rejected (non‑fast‑forward):
git fetch origin && git rebase origin/main
(then resolve & push). - Rebased your feature and need to update PR:
git push --force-with-lease
. - Can’t switch branches due to local edits: commit,
git stash
(use-u
to include untracked), or discard.
6.12.7 Quick reference of commands mentioned
# See differences between layers
git status
git diff
git diff --staged
# Stage/unstage in parts (hunks)
git add -p
git restore --staged -p <file>
# Stash changes
git stash push -m "wip" # tracked files
git stash push -u -m "wip" # include untracked
git stash list
git stash show -p stash@{0}
git stash pop # apply & drop top entry
# Safe push after history rewrite
git push --force-with-lease
If you want, tell me which platform you host on (GitHub/GitLab/etc.) and whether you prefer “squash” or “rebase” merges—I can give you a one‑page checklist of exact settings and the minimal command set your team should follow.