GIT

GIT

The following is a collection of notes I took from reading the book on Git, Progit. Its a page I am still growing. (I got enough of the book to use Git with reasonable ease and have for long not updated the page). I am still sure it can be a good starting point or reference for most of the basics and more. I also include links to articles from Atlassian that I used for deep dives where I felt I needed more explanation. Hope this helps. Also, you should really check out the last chapter of the book Progit. I haven't added notes for it yet but it sure is an interesting read. It's on git internals and how the core commands work on the inside. (The plumbing commands that is).

VCS: Version Control System: GIT (intro)

Why the need for version control?

  • Recovering old versions with ease
  • Peace when new versions get messed up or get lost
  • Freedom to easily switch between multiple versions of the same document

The different kinds of version control

1. Manually Copying copies of a file across multiple locations

  • Problems with this approach

    • Forgetting what version is in what file system location.
    • The burden of choosing a naming system and maintaining it.
    • Overwriting files copied to some folder for version control.

2. Version control with databases

  • One file has multiple instances of it stored in some databases (Local version control)

    • Examples

      • RCS: (Revision control system)

        • Successor to Source Code Control System
        • Keeps diffs or patch sets (Or the small changes in files, as they change)
        • Restores files by combining these diffs
  • How it works and why it ain't cool (or any VCS like it)

    1. User A locks the file – Before editing
    2. User A runs a command (e.g., co -l file.txt) to “check out” the file with a lock.
    3. RCS marks the file as locked by User A in the repository.
    4. User B tries to check out the same file
    5. If User B attempts to edit the same file (with co -l), RCS will display an error message like:
        co: error: revision 1.3 already locked by user A
    6. User B must wait – User B cannot make changes until User A finishes and checks the file back in (unlocking it).
    • Problems with this approach

      • Only one user can work on a file at a time

3. Central version control systems

  • Arised from the need to collaborate between developers (beyond what was then currently supported).

    • Examples

      • CVS, Subversion, Perforce
    • How it works

      • Its basically a single server with multiple devs connected each checking in and out.
      • Each dev only has the latest version of whatever work is being worked on.
 As in:  git clone --depth 1 <url>
  • Problems with this approach

    • The server is a single point of failure (Power problems affect all)
    • Disk problems affect all past history

      • Only what devs have locally is kept intact (which isn't all there is about the project).
      • Dev's only have the latest updates.

4. Distributed VCS (DVCS)

  • All problems from the previous version control methods led to this as the solution.

    • Single point of failure issues. (CVCS)
    • Network dependency for most operations.
    • Slow operations arising from network dependency.
  • How DVCS is different.

    • Clients mirror a repo's full history and not just the latest snapshots or versions of files.
    • Every clone is a full backup of the server data.
    • The system as it is designed allows for hierachical models impossible in vcs's previously mentioned.

      • Explained and demonstrated later in the book when talking about Workflows.
       # an example of this is the lieutenant workflow used by the linux kernel
       [Blessed/Main Repo]"truth" / official release
       [Integration Repo]          ← lieutenants merge & verify
        ↑           ↑
       [Dev Repo A]    [Dev Repo B]       ← individual contributors
  • Examples of DVCS

Git's origins

Differences between Git and other VCSs.

File storage

  • Others store data as changes to base files over time. The changes are called deltas.

    • For instance, there's 3 files a,b,c.

      • Version one could be a change in file a.
      • Version two could be a change in files b and c.
  • Git thinks of version control as snapshot storage.

    • A change triggers a storage of new state
    • A commit without a change has git skipping generation of state and pointing to already existing such state
    • If we have files a, b, c in Version 0

      • Version 1 could be a change in a. So we have New state for a, then pointers to Version 0 state for files b and c
      • Version 2 could be a change in b and c. So we have new state for b and c, then pointers to version 1 for a
  • Git stores it all locally so a user can commit changes as often as they want even without internet connection unlike CVS like Perforce. (They talk about that here.)

Integrity

  • Git checksums everything with SHA-1 before it is stored.
  • Any change will therefore be known.
  • It is hard to do anything that is oneway or not undoable as all actions are recorded in the repo database.
  • Virtually all changes can be thought of to be reversible.

The three Git state files

  1. Modified

    • Changed but not yet committed to the database.
  2. Staged

    • Marked a modified file as candidate for the next commit snapshot.
  3. Committed

    • Safely stored in git database. Ready for next push.

Three main sections of a git project

  1. The working directory

    • Single checkout of one version of the project pulled from the git repo (or database)
  2. The staging area

    • Where staged data lives
    • It comes from working area through staging
  3. The .git directory or Repository

    • Where committed data lives (objects and metadata)
    • Comes from staging area through commits

Git configuration

A brief summary on git configs

  • There's different configs for Git that can exist on a single system.

    /etc/gitconfig
    This applies to all users
    ~/.gitconfig OR .config/git/config

    This is user specific.

    1. Written to using the –global flag with the git config command.
      git config --global ...
    .git/config

    This one is repo specific.

    • Writtent to using the –local flag with the git config command.
  • For viewing settings origins

     git config --list --show-origin
  • For configs with keys defined more than once, git uses the last value for each unique key it sees.

Some config related Git commands

Identity configs
  git config --global user.name ...
  git config --global user.email ...
Editor configs
   git config --global core.editor vim
Default initial branch for repos
  git config --global init.defaultBranch branch_name
Listing settings
 git config --list
Finding rogue config values origins
git config --show-origin config_value.autoUpdate

Getting help with git

 git help _subcommand_for_which_you_need_help_
 git _command_ -h # for summrized help

Git Basics

Briefly on how Git works

  • Git stores data as series of snapshots. (not a series of changesets/deltas like other vcs).
  • Staging a file does the following:

    • It creates checksum (SHA-1) for each snapshot.
    • It stores version in local repo as blobs.
    • It adds the blob checksum to staging area.

On Git Commits

  • A commit command does the following:

    • It stores commit object with pointer to staged created snapshot.
    • It checksums each subdirectory in the commit.
    • It stores the directories as commit tree in local repo.
    • It creates commit object.
  • On the structure of the commit object

    • Right after the first commit, `master` (or whichever name for the active branch) is written to .git/refs/heads
    • Commit object contains

      • A pointer to root project tree (a hash, and another hash)
      • The commit author email, name and pointers to commits before it
    • Initial commits have no parents
    • Normal commits have 1 parent
    • Merge commits have multiple parents
  touch file1 file2 file3
  git add .
  git commit -m 'initial commit'
  # this puts 5 files .git/objects
  # one for each file, one for the commit, one for the root directory hash/checksum

On repository creation

  • There's two ways to create a repository

    • Creating a local directory and turning it into a repo

      cd dir_that_will_be_repo_name
      git init
        git add *.c # assuming all files are .c files
      git add LICENSE # assuming you have a licence file
      git commit -m 'commit_message'
    • Cloning a repo from some other location

      git clone repo_url # creates a dir with the cloned repo name and initializes a .git dir then pulls data from url to dir
      # to clone into a different dir
        git clone repo_url desired_dir_name
  • Supported protocols for cloning include:

    • git://
    • user@server:…:/reponame
    • https://

Recording changes to repository

The different types of files in git

Tracked files
Files that Git knows about. (unmodified, modified, staged)
Untracked files
Any file that was not in the last snapshot.

More on Git file types

  • Committed files are marked as unmodified files (after the commit action).
  • Unmodified files can be moved to the untracked state.

      git rm --cached <file>
      # for recursive removal
      git rm --cached -r directory
      # to prevent retracking
      echo 'filename' >> .gititnore
      git add .gitignore
      git commit -m 'stop tracking filename'
  • File status can be checked with the command 'git status'.

     git status # run in a repo
    • The output shows any untracked files (not in the .gitignore file) or tells if the tree is clean (no new modifications, everything commited)
    • It also tells what branch is currently active
  • Files can be added to tracked status with the `git add` command.

      git add filename # this will eliminate the file from the list of untracked files in the repo listed when git status is run. it will be included in the next commit.
  • A modification to a tracked file is recorded as an unstaged change that can be staged with:

    git add file-name
  • Changes to staged files have them marked both as staged and unstaged.

    • Its changes that are staged not files hence this makes sense.
  • A more simplified version of status is achievable with `git status -s`. Below is explanation for this command's output:

    - ?? : New files not yet tracked
    - M  : Modified tracked files (Modified twice is shown with 2 M's) (added then modified before a commit)
    - A  : New files in staging area

Ignoring files in Git

  • Not all files in a project need to be tracked by Git.
  • One way Git ensures this is using the .gitignore file.
  • The syntax for ignoring files in the .gitignore files is somewhat like `regex`. Its the glob pattern syntax.
  • A sample .gitignore file can look like so.

      .a*
      !lib.a # even if ignoring .a files, make this an exception
      /TODO # ignore TODO file in current dir not subdir/TODO
      build/ # ignore files in dir named build
      doc/*.txt # ignore all .txt files directly under doc/
      doc/**/*.pdf # ignore all pdf files in dir and subdirs for doc/
    • In the above file

      • Asterisk matches anything except a slash
      • Escape char is '\'
  • Sample .gitignore files can be found here.
  • Nested .gitignore files only apply in directories where they are found.
  • I also have an article written on this area of git that you can find here.

Working with staged files and file changes

  • Viewing staged and unstaged changes

     git status
  • Viewing what's changed but not yet staged

      git diff # Compares what's in working directory with what's in staging area.
  • Interpretation of the output from the `git diff` command. (wrapped in hashtags)

    • Git first determines what files were passed to the diff command.
    • It then tells what symbols changed in each of the files and the differences between the changes in each are determined.
    • It then outputs something like: @@ -34,6 +34,8 @@

      • Meaning: from line 34 in the file whose changes are denoted by symbol '-' , 6 lines have been extracted .. and from file whose changes are denoted by symbol '+', 8 lines have been extracted.
  • Viewing staged changes ready for next commit (these are in staging area)

    git diff --staged # comparing whats staged with what's commited (or whats in local repo)
  • There's more about the git diff command right here.

    • Topics touched upon in the linked article include but ain't limited:

      • Comparison of pdf files
      • Comparison against other indices than the local repo and staging area
      • Configuration of converters for different forms of binary files

        • pdfs with text2conv
        • images with exiv2
      • Comparing branches with the `..` operator.
      • Briefly on the `…` operator
      • Comparing two files to a third or two branches (their heads) to a third

Removing files from Git

  • Removing files from git is removing them from Git's staging area.

      rm projects.md # assuming projects.md was new to staging area 
      git status # will show the removal 'change' is unstaged
      git rm projects.md # remove from staging area. (stage removal of file from repo: happens on next commit)
  • Removing a staged file by force

      git rm -f file_name # deletes file from local too (ignores if there was any uncommited changes relating
      to the file).
      git rm --cached file_name # deletes file only from git, file still appears under untracked
  • Dealing with Git's special globbing syntax quirks during removal

      git rm log/\*.log # git does its own filename expansion, so that backslash behind the "*"
      # escapes shell expansion
      # passes * as is to the git command
      git rm \*~ # same concept, remove all ending in ~

Renaming files in Git.

  git mv README.md README
  # equivalent to the 3 commands below
  mv REAME.md README
  git rm README.md
  git add README

Viewing Git commit history

  git log # in a repo to show commit history from last commit (at top) downwards
  # lines of output are: commit hash, commit author, commit date, commit message, space

Some common git log options

  • Show difference introduced with -p and limiting entries displayed with -n
  git log -p -2 # limit to 2 lines of output
  • See abbreviated stats for each commit

      git log --stat
  • The pretty option: prettify output as per arguments passed to the –pretty flag

      git log --pretty=oneline
      git log --pretty=format:"%h - %an, %ar : %s" # hash, author name, avg age relative, subject or commit message
    • More pretty specifiers available at.. pg43 progit
  • Combine single line output with graph

      git log --pretty=format:"%h %s" --graph
      # branch merge graph, history of commits with hashes and subjects
    • More options

        - -p  --stat, --shortstat, --name-only, --name-status, --abbrev-commit, --relative-date
        --graph, --oneline, --pretty (oneline, short, full, fuller)
    • Limit log output by date

       git log --since=2.weeks # date can follow the format: "2008-01-15" or "2 years 1 day 3 minutes ago"
      • An alternative time specification flag can be '–until', '–after'
      • More granular matching available with '–grep , –all-match' and others like '–author, –committer'
      • Git's pick axe (see what changes happened related to some string)
       git log -S string
    • View only changes that affected some folder's files

       git log -- path/to/file
    • Sample complex logging command (there's notes on git command aliases down below if the length feels overwhelming).

      git log pretty="%h - %s" --author='name' --since='' --before='' --no-merges -- t/
    • More on git logging here.

Undoing things in Git

When you commit but forget something behind

  • git commit –amed # takes staging area and uses that for replacing latest commit

      git commit -m 'initial commit'
      git add forgotten file
      git commit --amend # ends up with 1 commt replacing previous one
      # helps clean out useless commit messages 'opps last commit'
      # pro tip: Don't force push ammends. Only ammend local commits

When wanting to unstage some file

  git add *
  git status
  git reset HEAD file_that_should_be_reset # git restore --staged filename

When 'unmodifying' modified files.

  git checkout -- filename # git restore filename
  git status # above command replaces filename from latest commit version or from the staging area

Working with remotes

A Git Remote

A wersion of a Git project stored at some uri than the local repo.

  • This does not necesarrily have to be a remote server off one's machine.
  • It could be on some different location on the machine the project is hosted on.

Showing remotes

  • Displaying remote names

    git remote
  • Displaying each available remote's urls

    git remote -v

Adding new remotes to a project repo

git remote add <shortname> <url>

Getting all info on remotes that ain't in local repo

git fetch remote
On the fetch command.
  • It pulls but does not merge downloaded data with local data. (More on merging in the next section)
  • 'git pull' on the other hand auto merges after downloading changes for a local branch set to track some on a remote repository.
  • Git fetch gives warning if the 'pull.rebase' (automerge handle) is not configured (More on rebasing in later sections)
  • This can be configured with :
 git config --global pull.rebase true (to auto merge on pull)

Pushing changes to Upstream

git push <remote_name: often origin> <branch to push>
# This  works only if pusher has write access on remote.
# if branch to push does not exist on target remote, it will be created then written to.

Seeing more info about a remote

 git remote show <remotename> # ignore last param to get more detailed info on all remotes

Renaming and removing remotes

 git remote rename original new # Changes auto propagate across repos (local and others)
 git remote remove paul # Deletes remote paul

Git tagging

  • Tagging can and is used for version control.
  • Other than mark where some version starts with the commit hash (which is humanly unreadable, Git provides the means for a human readable means for versioning).

A quick summary on tagging

  • listing existing tags

     git tag
  • listing tags matching some pattern

     git tag -l 'v1.8.5.*' # -l or --list mandatory for wildcard tag search

Tag creation

  • Tag types and their properties

    • Lightweight tags

      • Do not change
      • Are like branches
      • Are pointers to specific commits
    • Annotated tags

      • Stored as full objects in the git db (more about this in the git internals section).
      • They are checksummed.
      • Components of a git tag:

        • tagger name, email, date
        • tagging message
  • Annotated tags

    • Creation

       git tag -a v1.4 -m 'my version 1.4' # if msg unspecified, editor spawned to collect it.
       git tag # will list v1.4 among tags
  • Lightweight tags

    • Strucuture: Basically the commit's checksum
    • Creation

      • git tag v1.4-lw # no -a or -s
  • Tagging by commit hash

    • Tagging is usually done while some version is being released.
    • However, if one remembers to tag a version after they are way passed the commit that marked the version's end, the commit's hash can be used.
      git log --pretty=oneline
      git tag -a v1.2 shorthashfromprevcommand
  • Tag sharing

    • Git defines explicit means for sharing tags. (aint shared along with objects in git push)
    • Syntax: `git push origin <tagname>`
    • Pushing multiple tags

      git push origin --tags
    • Pushing ony annotated tags

       git push <remote> --follow-tags
  • Tag deletion

    git tag -d v1.4-lw # not removed from remote
    • Deleting from remote can be done in 2 ways

      1. git push origin :refs/tags/v1.4-lw
      2. git push origin –delete <tagname>
  • Tag checkout

    • git checkout <tagname> # puts one in detached state (A state in which they are not on any branch)

      • Any changes made and committed wont go no where
      • Changes made here will only be reachable by the exact commit hash for the change
      • A solution to that is naming a branch during checkout.
      git checkout -b version_name v2.0.2
      # creates branch called version_name , placed at commit pointed to by v2.0.2
  • More details on tagging right here.

Git aliases

  • Git aliasing is a means to shorten commonly used but painstakingly long git commands
  git config --global alias.co checkout
  git config --global alias.br branch
  git config --global alias.ci commit
  git config --global alias.st status
  • Some of Git's inbuilt aliases
  git config --global alias.unstage 'reset HEAD --'
  # the two below are one in the same
  git unstage fileA
  git reset HEAD -- fileA
  # another
  git config global alias.last 'log -1 HEAD'
  # git last now runs: git log -1 HEAD

  # aliasing external commands
  git config --global alias.visual '!gitk' # notice the `!`

Git branching

What happens on branch creation?

  • A new pointer in .git/refs/heads is created. It points to current the commit. It's the branch displayed when the command 'git branch' is run.

      git branch
  • If no commits at all have been made in a repo, there's no concept of a branch since a branch is simply a pointer to a commit checkum, a snapshot in the project history.
  • The `HEAD` ref still points to nothing that is.
  • Switching branches

     git switch branchname
     # The above only works if the branch 'branchname' exists. To create one if it does not, use.
     git checkout - b branchname
     #OR
     git switch -c branchname
  • This action moves HEAD pointer to `branchname`.
  • Git log usually only displays activity from current commit point backwards.
  • Commits are 41 chars long: 40 chars for the sha-1 hash and a n\/ char

      ls .git/objects/e1 | wc -c # where e1 is the first 2 chars of the commit
    • When you switch to a branch, git resets wdir to look like it did the last commit tht happened on that branch.

Merging and deleting branches

A brief intro
  • Merging is aligning one branch's current state with another branch's so they are both on the same page.

    • Reconciling forked histories like one article puts it.
  • Merging in Git is done with the git merge command.

    # in branch to receive merge
    
     git merge branch_whose_changes_to_pull_in
Merge types
  • A fast forward merge means the two merged branches had a common latest commit. There was no divergent work. One branch is basically only behind the other like 5 is behind 10)
  • The divergent merge (merge by recursive strategy Or 3-way merge). Example below.

      touch file1.txt
      git init . # on branch master
      echo 'some' > file1.txt
      git commit -a -m 'initial commit'
      git switch -c someotherbranch
      echo 'another change' > file1.txt
      git commit -a -m 'some other branch commit'
      git checkout master
      git log --oneline --decorate --graph --all
    • Git gets common parent for both branches
    • Git gets each branch's tip
    • The three are merged
    • A merge commit is created (new common tip)
Merge conflicts
  • These result from changing some common part of the same file differently on two different branches then requesting

a merge.

  • Interpritting merge file syntax
  • Each branch's contribution to change in a file is shown with unique symbols.
  • "HEAD" indicates where the current branch's changes start.

    • That includes all lines after head prepended with <<
  • The current branch's changes for each section are closed of with a line of '==' dashes.
  • What comes after is the 'other' branch's changes for the same secion.
  • They are prepended with ` >>>`

    • To resolve the conflict, you delete all the separation indicators and choose

from the different changes what should remain in the merge commit.

  • A merge commit conflict resolution can be cancelled by deleting the file `.git/MERGE_HEAD` and fixing the branches

to make it so come next commit a merge conflict resolve is not triggered.

Some common merge and branch related commands
  • See last commit on each branch

     git branch -v
  • See merged branches

    git branch --merged # ignore unmerged branches
    git branch --no-merged # show unmerged branches
    git branch -D branchname # delete unmerged branch , -d is for normal deletion
    git branch --no-merged branchname # include branches that aint merged into branchname
  • Branch renaming

    • Locally renaming branch
       git branch --move bad-branch-name new-branch-name
  • Pushing name change to remote (its like creating a new branch then setting it as default tracker)
       git push --set-upstream remote_name new-branch-name
  • Deleting old branch from remote
git push origin --delete bad-branch-name
  • Renaming branch
        git branch --move oldname newname
       # Pushing change:
        git push [origin] --set-upstream remote_name newname
       # some intermediary actions after taking this action
       # adjust build.release scripts, update refs to old branch in docs
       # close or merge any PR targetting old branch
       # RUN: git push origin --delete oldname
  • Viewing all branches, both local and remote

      git branch --all

Branching workflows

  • A project can have more than one branch running in parallel.
  • Classification for the branch types is mainly based on how long it takes until work from the branches is merged into the main branch or , until they are killed.
  • Different branches can be used for different development stages.

    • One branch for stable code (sources from the dev branch)
    • One for development (sources from the topics branches)
    • One for topics (the most short lived branches)
    • One for pu (proposals)
  • The stable branches (well tested and finally merged into main code) are 'further down' in commit history line while the 'bleeding edge'(latest updates) is further up.
  • The Long running branches

    • Some project features can't ship incrementally so work in these branches is accumulated over weeks or months.
    • The diffs for these branches are large by the time they merge.
    • There's for that reason high probability for merge conflicts. (for the huge divergence from main)
    • A case for long running branches here.
  • Topic branches

    • These are useful for quick fixes
    • A developer creates the branch, works on feature, tests it, then deletes the topic on merging changes into main branch. (or dumping the changes).
    • They are also called feature branches.
    • See pg 85 of the book Progit for a visual demo.
    • More details on these branches from here.

More on remote branches

Remote branches

They are basically references stored in remote repositories.

  • Viewing all remote references can be done with:

    git ls-remote remote_short_name
    #or
    git remote show remote_name
Remote tracking branches

They are references to the state of remote branches but stored on the local repo.

  • They are immovable local references updated by git on network activity. git fetch that is.
  • Their name format :: <remote>/<branch>
?

What happens when you clone a remoterepo with the branch master?

  • Git creates for you a master branch and stores the ref to the server that's the source under the remote name 'origin'.
  • Git brings commit history for master to local and stores that under `origin`.
  • Both the `HEAD` for `origin/master` (the remote tracking branch) and your master's HEAD point to the same commit at this instant.
  • We then have two masters then.

    • Your master

      cd .git
      cat HEAD # outputs /refs/heads/master
    • Origin/master: A remote tracking branch

      ls /refs/remotes/origin # contains an entry for master
  • On any remote change( say you push something to remote/master) or someone else does, the next pull will update origin/master to reflect the changes.
  • Changing default remote name on clone from `origin` can be done with

     git clone -o local_remote_name
    • Remote tracking branches will then be under local_remote_name/branch_name (say: origin/master)
  • Doing remote synchronization for remote tracking branches

      git fetch <remote>
      # git fetch local_remote_name
      #This evaluates the server local_remote_name points to and
      # fetches any new data from it then updates local refs.
  • Adding remotes to a repo

    git remote add remote_name remote_url
    #Sets a local tracking branch under remote_name for the remote at  url: remote_url

Pushing branches

  • Pushing local branch to remote

    • If there's no copy of the branch on the remote repo yet,it will be created during the push.

      git push origin serverfix
      # serverfix remote is  internally expanded to : refs/heads/serverfix:refs/remotes/serverfix
      # Use my serverfix and update remote's serverfix
      # another way to get the same work done would be
      git push origin serverfix:serverfix
    • The push command's synopsis is therefore: `git push origin localsourcebranch:remotedestinationbranch`.
    • Fetching a remote with branches not locally available does not auto create locally editable versions of them, only remote tracking branches. Remote tracking branches can be referenced via the syntax remotename/branch-name on local repo.
    • Checking out a remote-tracking branch automatically creates a local tracking branch. (An upstream branch is what the remote tracking branch is to the branch checked out of it.)

      git checkout -b serverfix origin/serverfix
      #OR: git checkout serverfix

Tracking branches

  • When git is dealing with local branches in direct relation to some remote branch, Git automatically deduces the origin for pulling and pushing.
  • Manually setting upstreams (default origins for pull and push that is)

     git branch -u origin/upstreambranchname
      # sets branch head's pointing to to track upstreambranchname
  • Short hand with upstreams

    • @{u} means: upstream
      git merge @{u} # Merge upstream changes into tracking branch
  • See tracking information based off last fetch action

     git fetch --all; git branch -vv
  • Fetching does not merge downloaded changes with tracking branches, pulling tries to. git pull is essentially a combination of a git fetch and git merge.
  • Deleting remote branches

    git push remotename --delete branchname
    • Some notes on deletion

      • Actual removal is done by the 'garbage collector'.
      • Only the pointer to the branch is removed by above action.
      • This sounds like reference counting type of garbage collection… interesting.

Git Rebasing

A brief summary on rebasing

  • It is alternative to the `git merge` command.
  • Rebasing is taking all changes that happened in one branch and replaying them on top of another another branch.
  • A branch's base is the commit at which the branch in question broke off its parent. (at the point of the branch's creation)
  • Changing that commit, branching point commit that is, to some other commit (that is another branch's tip) is called "rebasing".
  • Rebasing is changing the base of your branch from one commit to another making it appear as if you'd created your branch from a different commit.
  • It allows for a cleaner git history line.A linear history.

A textual example for git rebasing

  • With two branches A and B, with the second branch splitting into two : B and C, And in need of switching C's base branch from B to A
  • Rebasing synopsis

      git rebase  --onto third what_to_skip what_to_rebase
      # for the above example
      git rebase --onto A B C
  • Rebasing arbitrary branches

      git rebase basebranch topicbranch # moves topicbranch's base to basebranch's tip
  • After a successul rebase, the merge between the rebase base branch and the new tip is a fast forward type merge. (see previous notes on merging to know what a fast forward merge is).

Some guidlines when rebasing.

  • Do not rebase commits that exist outside your repo and that people may have based on your work. It can lead to really messy effects when your team mates pull the work in.
  • Rebase local changes before pushing to clean up your work. But never rebase anything that you've pushed somewhere.

      git pull --rebase (to fetch and rebase vs fetch and merge)
      git config --global pull.rebase true # to default to rebasing on bull vs the default that is merging

Git Merge vs Git Rebase

  • Merging shows a truer history for a project's evolution.
  • Rebasing provides means for having a cleaner git history.

References: past, current and future