What lies inside Git?
655a20f99af32926cbf6d8fab092506ddd70e49c
Mainly:
Each object is identifiable by its SHA-1 hash.
cat .git/refs/heads/main
# 7c66409021358486e63d2d40c9b07e2c35e8124d
cat .git/refs/remotes/origin/dev
# c29dc332ac3eebebffc5726e16d0e91df170103f
cat .git/refs/tags/v2.6.3
# d49de0ec577052db3e47e2baf5aff0be738637ac
Tip: In PowerShell, you can use gc
(alias for Get-Content
) instead of the cat
command.
Porcelain:
commit
, log
, merge
, pull
, push
, status
, β¦Plumbing:
cat-file
, commit-tree
, hash-object
, ls-files
, merge-base
, rev-parse
, β¦.git
tree.git
βββ HEAD ref: refs/heads/main
βββ index
βββ objects
β βββ 59 blob [test.txt] 'version 1'
β βββ 4dc0e39bc4468ee19c67e65d37b97eb963b68b
β
β
β
β
β
β
β
β
β
β
β
β
β
β
β
β
βββ refs
βββ heads
|
βββ tags
.git βββ HEAD ref: refs/heads/main βββ index βββ objects β βββ 59 blob [test.txt] 'version 1' β β βββ 4dc0e39bc4468ee19c67e65d37b97eb963b68b β βββ 67 tree [blob 594d] β β βββ 4d4d31b97233152f3be1825cc9e765fa2b2859 β βββ f8 commit [tree 674d] "First" β βββ 0a04ee3dfbeb5eb666ade615abc617c1ea20e3 β β β β β β β β β β β β βββ refs βββ heads | βββ main f80a... βββ tags
.git βββ HEAD ref: refs/heads/main βββ index βββ objects β βββ 59 blob [test.txt] 'version 1' β β βββ 4dc0e39bc4468ee19c67e65d37b97eb963b68b β βββ 67 tree [blob 594d] β β βββ 4d4d31b97233152f3be1825cc9e765fa2b2859 β βββ f8 commit [tree 674d] "First" β β βββ 0a04ee3dfbeb5eb666ade615abc617c1ea20e3 β βββ f0 blob [test.txt] 'version 2' β β βββ d983103c610431663d84b3012d1b172f2f52ea β βββ 37 tree [tree 674d, blob f0d9] β β βββ 87931e43c8baf51f3ffafc44f6394651a505ca β βββ 53 commit [tree 3787, par. f80a] "Second" β βββ 9f7e662b0fa2ceb0df1dc9332179b06e5cdaec β β β β β β βββ refs βββ heads | βββ main 539f... βββ tags
.git βββ HEAD ref: refs/heads/main βββ index βββ objects β βββ 59 blob [test.txt] 'version 1' β β βββ 4dc0e39bc4468ee19c67e65d37b97eb963b68b β βββ 67 tree [blob 594d] β β βββ 4d4d31b97233152f3be1825cc9e765fa2b2859 β βββ f8 commit [tree 674d] "First" β β βββ 0a04ee3dfbeb5eb666ade615abc617c1ea20e3 β βββ f0 blob [test.txt] 'version 2' β β βββ d983103c610431663d84b3012d1b172f2f52ea β βββ 37 tree [tree 674d, blob f0d9] β β βββ 87931e43c8baf51f3ffafc44f6394651a505ca β βββ 53 commit [tree 3787, par. f80a] "Second" β β βββ 9f7e662b0fa2ceb0df1dc9332179b06e5cdaec β βββ dc blob [new.txt] 'new' β β βββ 334bff12fb7d7404c79935fa3ba535c3bb28d0 β βββ b0 tree [tree 674d, blob f0d9, blob dc33] β β βββ ea95a512bad604278bcc96e8b8e726b462e010 β βββ 62 commit [tree b0ea, par. 539f] "Third" β βββ e37a96f8f09d0421644817dea320108ceac481 βββ refs βββ heads | βββ main 62e3... βββ tags
.git
for a real projectpybrickz/.git β COMMIT_EDITMSG last commit message edited in the local repository β config local configuration, applies only to this repository β description don't worry about it β FETCH_HEAD remembers what was last fetched from the remote repository β HEAD pointer to the current branch/commit β index binary list of paths and SHA-1 hashes, view content with `git ls-files --stage` β ORIG_HEAD previous state of HEAD, set by commands with potentially dangerous behavior β packed-refs packed references (heads, tags) ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects [β¦] ββββrefs [β¦]
.git/objects
pybrickz/.git β [β¦] ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects objects - blobs, trees, commits β ββββ00 β β 57f7cf16175d94fa850ad30918dffcd4cd850c β ββββ01 β β 4daec1e8a05a71852209c4caf9750bfe4717b1 ... β ββββfe β β 1c754ef352dece245b5f7a0d7047b048d7b1d9 β β 8a73f88812537678fde89e91c19c87623ff47c β ββββff β β 7e837bf1dc59b8835767fdcf789e308528498a β ββββinfo [β¦] β ββββpack [β¦] ββββrefs [β¦]
.git/refs
pybrickz/.git β [β¦] ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects [β¦] ββββrefs references - branches, remote branches, tags ββββheads [β¦] ββββremotes [β¦] ββββtags [β¦]
.git/refs/heads
pybrickz/.git β [β¦] ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects [β¦] ββββrefs ββββheads β dev β main β staging β ββββbugfix β β bugfix-1 branch created via `git branch bugfix/bugfix-1` β β bugfix-2 branch created via `git branch bugfix/bugfix-2` β ββββfeature β feature-A branch created via `git branch feature/feature-A` β feature-B branch created via `git branch feature/feature-B` ββββremotes [β¦] ββββtags [β¦]
.git/refs/remotes
pybrickz/.git β [β¦] ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects [β¦] ββββrefs ββββheads [β¦] ββββremotes β ββββgh β β main β ββββorigin β β dev β β HEAD β β main β ββββbugfix β β bugfix-2 β ββββfeature β my-awesome-feature-A ββββtags [β¦]
.git/refs/tags
pybrickz/.git β [β¦] ββββhooks [β¦] ββββinfo [β¦] ββββlogs [β¦] ββββobjects [β¦] ββββrefs ββββheads [β¦] ββββremotes [β¦] ββββtags v1.0.0 v1.0.1 ... v2.6.4 v2.7.0
.git/HEAD
HEAD
is a pointer to the current branch or commitDETACHED HEAD
is a situation where HEAD points to a commit that is not the head of a branch.git
directory, find the file with the hash that the slovak
branch points to.git rev-parse slovak
command.git cat-file -p
command multiple times, find out what content is in the hello.py
file on the slovak
branch.
-p
.After cloning the repository, all the objects that Git uses are located in the .git/objects
directory, but some of them may be packed in the pack
directory.
git clone https://github.com/bbrrck/hello.git
cd hello
ls .git/objects
# .git/objects/info
# .git/objects/pack
ls .git/objects/pack
# .git/objects/pack/pack-48cae0e3bd98461308f23caeb2cfcc3df0b34da8.idx
# .git/objects/pack/pack-48cae0e3bd98461308f23caeb2cfcc3df0b34da8.pack
# .git/objects/pack/pack-48cae0e3bd98461308f23caeb2cfcc3df0b34da8.rev
Manual unpacking of objects is possible using the git unpack-objects command. However, if we use this command on the files from the previous example, nothing will happen. This is because Git will not unpack objects that are already in the repository. Therefore, before unpacking the objects, it is necessary to move them to another part of the repository.
# Move the files with packed objects to a temporary directory
mkdir temp; mv .git/objects/pack/* temp
# Unpack the objects
cat temp/*.pack | git unpack-objects
# Delete the temporary directory
rm -rf temp
Manual unpacking of objects is not necessary outside of experimentation.
In Git, there are two main ways to integrate changes from one branch into another: merge
and rebase
.
merge
main
and feature
) and their latest common ancestormerge
rebase
feature
branch onto the main
branch means moving the start of the feature
branch to the end of the main
branchfeature
will be recreated on the main
branchrebase
rebase
?git rebase
on public or collaborative branches (especially main
)rebase
?merge
git clone https://github.com/bbrrck/hello.git hello-merge; cd hello-merge
git merge origin/french
# Auto-merging hello.py
git merge origin/slovak
# CONFLICT (content): Merge conflict in hello.py
# ... resolve the conflict ...
git add .
git commit
# [main cef4a72] Merge remote-tracking branch 'origin/slovak'
rebase
(french)git clone https://github.com/bbrrck/hello.git hello-rebase; cd hello-rebase
git checkout french
git rebase main
# Successfully rebased and updated refs/heads/french.
git checkout main
git merge french
# Updating 0297280..5f6f019
# Fast-forward
# hello.py | 11 ++++++++++-
# 1 file changed, 10 insertions(+), 1 deletion(-)
rebase
(slovak) - conflictgit log --oneline --graph --all
Merge:
* cef4a72 (main) Merge branch 'slovak' |\ | * 163a9c3 (slovak) Add docstring for slovak | * bd67d8d Fix slovak | * 75fcf88 Add slovak * | bc3f86b Merge branch 'french' |\ \ | * | a31caf9 (french) Add docstring for french | * | 6d348f3 Add french | |/ * / 0297280 Add docstring for default |/ * 4b4a8ad Add hello.py * 60d4d94 Initial commit
Rebase:
* ab2fda1 (main, slovak) Add docstring for slovak * 806b97a Add slovak * 5f6f019 (french) Add docstring for french * ea40a3b Add french * 0297280 Add docstring for default | * 163a9c3 Add docstring for slovak | * bd67d8d Fix slovak | * 75fcf88 Add slovak |/ | * a31caf9 Add docstring for french | * 6d348f3 Add french |/ * 4b4a8ad Add hello.py * 60d4d94 Initial commit
git log main --oneline
Merge (10):
cef4a72 (main) Merge branch 'slovak' bc3f86b Merge branch 'french' 0297280 Add docstring for default 163a9c3 (slovak) Add docstring for slovak bd67d8d Fix slovak 75fcf88 Add slovak a31caf9 (french) Add docstring for french 6d348f3 Add french 4b4a8ad Add hello.py 60d4d94 Initial commit
Rebase (7):
ab2fda1 (main, slovak) Add docstring for slovak 806b97a Add slovak 5f6f019 (french) Add docstring for french ea40a3b Add french 0297280 Add docstring for default 4b4a8ad Add hello.py 60d4d94 Initial commit
git clone https://github.com/bbrrck/zoo.git zoo-merge
git clone https://github.com/bbrrck/zoo.git zoo-rebase
zoo-merge
repository:
origin/krokodil
and origin/gorila
branches into the local main
branch using the git merge
command.(continued on the next slide)
zoo-rebase
repository:
gorila
branch and rebase it onto the main
branch using git rebase
. Resolve any conflicts that arise.main
branch and git merge
the gorila
branch into it.krokodil
branch and rebase if onto the main
branch using git rebase -i
. Mark the middle commit as fixup
. Resolve conflicts.main
branch and git merge
the krokodil
branch into it.git log
command to compare the state of both repositories.git merge --squash
creates a single commit on the target branch.
Usage:
* cef4a72 (main) Merge branch 'slovak' |\ | * 163a9c3 (slovak) Add docstring for slovak | * bd67d8d Fix slovak | * 75fcf88 Add slovak * | bc3f86b Merge branch 'french' |\ \ | * | a31caf9 (french) Add docstring for french | * | 6d348f3 Add french | |/ * / 0297280 Add docstring for default |/ * 4b4a8ad Add hello.py * 60d4d94 Initial commit
* f3492de (main) Squash french * d23ef42 Squash slovak * 54b75b3 Add docstring for default | * 437cd19 (slovak) Add docstring for slovak | * 5a92065 Fix slovak | * c1344d5 Add slovak |/ | * 0962e07 (french) Add docstring for french | * 7571e67 Add french |/ * de2c4ac Add hello.py * 944ce4e Initial commit
cef4a72 (main) Merge branch 'slovak' bc3f86b Merge branch 'french' 0297280 Add docstring for default 163a9c3 (slovak) Add docstring for slovak bd67d8d Fix slovak 75fcf88 Add slovak a31caf9 (french) Add docstring for french 6d348f3 Add french 4b4a8ad Add hello.py 60d4d94 Initial commit
f3492de (main) Squash french d23ef42 Squash slovak 54b75b3 Add docstring for default de2c4ac Add hello.py 944ce4e Initial commit
After performing a squash merge, you should always delete the feature branch.
git revert
git revert HEAD # remove changes made in the last commit
git revert HEAD~1 # remove changes made in the second to last commit
git revert d49de0 # remove changes made in the commit with hash d49de0
git revert
creates a new version and does not change the repository history.
git reset
git reset --hard
changes the repository history and can cause file loss.
reset
vs revert
vs checkout
Command | Context | Usage |
---|---|---|
git reset |
Commit | Discard commits in a private branch or discard uncommitted changes |
git reset |
File | Remove a file from the staging area (from the index) |
git checkout |
Commit | Switch between branches or view old versions |
git checkout |
File | Discard changes in the working directory |
git revert |
Commit | Revert commits in a public branch |
git revert |
File | (N/A) |
git revert --no-commit $bad_commit # revert the commit, but do not save changes
git reset HEAD . # unstage the changes
git add --patch . # stage the changes that should be *reverted*
git commit # create a commit to revert those changes
git checkout -- . # discard changes that should not be reverted
Note: The changes we add using the git add --patch
command are the changes we want to revert, not the changes we want to keep.
Moving the last 3 commits from main
to a new branch feature
:
If the old commit has already been pushed to the remote, after using git commit --amend
you need to push with git push --force
or --force-with-lease
.
If the old commit has already been pushed to the remote, after using git commit --amend
you need to push with git push --force
or --force-with-lease
.
In Git, there are many different workflows that differ in how they use branching. In this chapter, we will show some of the most commonly used workflows and their advantages and disadvantages.
The Git Workflows Warehouse project contains a catalog of 50 workflows and also a useful list of resources.
main
), no other branches are usedAdvantages:
Disadvantages:
Centralized workflow (Atlassian)
feature
branches, which are then merged into the main
branchAdvantages:
main
Disadvantages:
Git feature branch workflow (Atlassian)
feature
branches are short-lived and frequently merged into the main
branch (even several times a day)Advantages:
Disadvantages:
Feature-based deployment can be beneficial for teams that value the isolation of features and are willing to manage the complexities of merging these features back into the mainline. On the other hand, trunk-based deployment is suited for organizations that prioritize rapid integration and releases and have the infrastructure to manage continuous integrations and feature flags.
In recent years, with the rise of DevOps and agile methodologies, thereβs been a clear trend towards more frequent integrations and releases. This trend has made trunk-based development, with its emphasis on rapid integration and release, increasingly popular among many tech giants and startups alike. However, as with all methodologies, itβs essential to evaluate the specific needs and capabilities of an organization before adopting a deployment strategy.
Feature-Based Deployment vs. Trunk-Based Deployment by John Nochowitz
develop
, release
, and hotfix
branchesmain
- production branchdevelop
- development branchfeature
- development of new featuresrelease
- preparation for releasehotfix
- fixing bugs in the production versionA successful Git branching model (Vincent Driessen)
Advantages:
Disadvantages:
Gitflow is a legacy Git workflow that was originally a disruptive and novel strategy for managing Git branches. Gitflow has fallen in popularity in favor of trunk-based workflows, which are now considered best practices for modern continuous software development and DevOps practices. Gitflow also can be challenging to use with CI/CD.
Gitflow workflow (Atlassian)
The overall flow of Gitflow is:
develop
branch is created from main
release
branch is created from develop
Feature
branches are created from develop
feature
is complete it is merged into the develop
branchrelease
branch is done it is merged into develop
and main
hotfix
branch is created from main
hotfix
is complete it is merged to both develop
and main
Examples:
Making a Pull Request (Atlassian)
ssh-keygen # use default settings
ssh-keygen -t rsa -C "[email protected]" # compatible with most git providers
ssh-keygen -t ed25519 -C "[email protected]" # compatible with GitHub
git gc
)en | sk |
---|---|
branch | vetva |
clone | naklonovanie repozitΓ‘ra |
commit | zΓ‘znam |
commit message | popis zΓ‘znamu |
conflict | konflikt medzi verziami |
conflict resolution | rieΕ‘enie konfliktov |
diff | rozdiel medzi verziami |
merge | zlΓΊΔenie vetiev |
en | sk |
---|---|
pull | stiahnutie vzdialenΓ½ch zmien |
push | odoslanie lokΓ‘lnych zmien |
repository | repozitΓ‘r, ΓΊloΕΎisko |
remote | vzdialenΓ½ repozitΓ‘r |
snapshot | snΓmka |
staging area | prΓpravnΓ‘ oblasΕ₯ (tieΕΎ index) |
status | stav repozitΓ‘ra |
version | verzia |