11. VCS - Git

11.1. GUI

The standard GUI for git(1) is:

gitk
gitk --all

The commit tool is:

git gui

Other programs:

cola:The highly caffeinated Git GUI
qgit:QT interface to git trees, with stgit support.
gitg:Git repository viewer

11.2. github fork

After cloning a github fork and adding an upstream repository, everday repeating operation is syncing the github fork with upstream.

11.2.1. Syncing the github fork with upstream

  1. Clean up:

    git stash
    git checkout master # -f
    
  2. Update upstream:

    git fetch upstream
    
  3. Merge upstream:

    git merge upstream/master
    
  4. Get current work:

    git stash pop / apply
    git stash clear # if anything left on stash
    

11.2.2. Cloning a github fork

git clone git@github.com:wolfmanx/REPOSITORY.git

11.2.3. Adding an upstream repository

git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git

Example:

sheckley:.../3rd-party/w2ui/w2ui$ git remote -v
origin      git@github.com:wolfmanx/w2ui.git (fetch)
origin      git@github.com:wolfmanx/w2ui.git (push)
upstream    https://github.com/vitmalina/w2ui.git (fetch)
upstream    https://github.com/vitmalina/w2ui.git (push)

11.3. Quickstart

See status:

git status

Get updated info from remote repositories:

git fetch --all

Get and merge remote into local:

git pull

Show branches:

git branch
git branch -a

Update remote refs along with associated objects:

git push

Show remotes:

git remote -v

Go to specific commit (revision):

git checkout revision

Fix # HEAD detached at 1.7.1:

git checkout master -f

If you want to revert changes made to your working copy, do this:

git checkout . -f

If you want to revert changes made to the index (i.e., that you have added), do this:

git reset

If you want to revert a change that you have committed, do this:

git revert ...

Abort a merge:

git reset --hard HEAD

Remove changes:

git branch
git reset --hard HEAD

Create/apply patches:

git format-patch deadbeef..b00b5 # => 001-title.patch, 002-title.patch, ...
git format-patch master.. # everything on a branch

git format-patch master...branch # from merge point

git am *.patch # separate commits
# if there are problems
git am --continue
git am --skip
git am --abort

git apply *.patch # no commit, single patch

11.4. gitk(1)

Show current branch:

gitk

Show all branches:

gitk --all

Source: git - How to make gitk show only local branches? - Stack Overflow

gitk --argscmd='git for-each-ref --format="%(refname)" refs/heads'

or

gitk --argscmd='git rev-list --no-walk --branches --tags'

11.5. Tricks

11.5.1. Separate SSH Keys

Source: ssh - How to tell git which private key to use? - Super User

git config core.sshCommand "ssh -i ~/.ssh/id_rsa_example -o 'IdentitiesOnly yes' -F /dev/null"
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example -o 'IdentitiesOnly yes'" git clone example

11.5.2. Find the first commit of a branch

git log master..branch --oneline | tail -1

E.g.:

git log master..i18n-default-locale --oneline | tail -1
# 40f5c99 option i18n.notrans for language alias of C locale

git diff 40f5c99~1 i18n-default-locale >tg2-i18n-notrans.patch

11.5.3. Delete commits

See git rebase - Delete commits from a branch in Git - Stack Overflow

Assuming you are sitting on that commit, then this command will wack it…

git reset --hard HEAD~1

The HEAD~1 means the commit before head.

Or, you could look at the output of git log, find the commit id of the commit you want to back up to, and then do this:

git reset --hard <sha1-commit-id>

If you already pushed it, you will need to do a force push to get rid of it…

git push origin HEAD --force

However, if others may have pulled it, then you would be better off starting a new branch. Because when they pull, it will just merge it into their work, and you will get it pushed back up again.

If you already pushed, it may be better to use git revert, to create a “mirror image” commit that will undo the changes. However, both commits will be in the log.


FYI – git reset --hard HEAD is great if you want to get rid of WORK IN PROGRESS. It will reset you back to the most recent commit, and erase all the changes in your working tree and index.

Lastly, if you need to find a commit that you “deleted”, it is typically present in git reflog unless you have garbage collected your repository.

11.5.4. How to modify existing, unpushed commits

Best answer on Stack Overflow is: git - How to modify existing, unpushed commits?:

Question:

I wrote the wrong thing in a commit message. Alternatively, I’ve forgotten to include some files.

How can I change the commit message/files? The commit has not been pushed yet.


Amending the most recent commit message

git commit --amend

will open your editor, allowing you to change the commit message of the most recent commit. Additionally, you can set the commit message directly in the command line with:

git commit --amend -m "New commit message"

However, this can make multi-line commit messages or small corrections more cumbersome to enter.

Make sure you don’t have any working copy changes staged before doing this or they will get committed too. (Unstaged changes will not get committed.)

Changing the message of a commit that you’ve already pushed to your remote branch

If you’ve already pushed your commit up to your remote branch, then you’ll need to force push the commit with:

git push <remote> <branch> --force
# Or
git push <remote> <branch> -f

Warning: force-pushing will overwrite the remote branch with the state of your local one. If there are commits on the remote branch that you don’t have in your local branch, you will lose those commits.

Warning: be cautious about amending commits that you have already shared with other people. Amending commits essentially rewrites them to have different SHA IDs, which poses a problem if other people have copies of the old commit that you’ve rewritten. Anyone who has a copy of the old commit will need to synchronize their work with your newly re-written commit, which can sometimes be difficult, so make sure you coordinate with others when attempting to rewrite shared commit history, or just avoid rewriting shared commits altogether.


Use interactive rebase

Another option is to use interactive rebase. This allows you to edit any message you want to update even if it’s not the latest message.

In order to do a git squash, follow these steps:

# X is the number of commits to the last commit you want to be able to edit
git rebase -i HEAD~X

Once you squash your commits - choose the e/r for editing the message

Here is an automatic rebase for the dates

Change both author and commiter dates:

date="Mon Mar 17 12:08:55 2025 +0100"; LANG= GIT_COMMITTER_DATE="${date}" git commit --amend --no-edit --date "${date}"
git rebase HEAD~3 --exec 'date="Mon Mar 17 12:08:55 2025 +0100"; LANG= GIT_COMMITTER_DATE="${date}" git commit --amend --no-edit --date "${date}"'

Check the dates with:

git log --format=fuller

Important note about Interactive rebase

When you use the git rebase -i HEAD~X there can be more than X commits. Git will “collect” all the commits in the last X commits and if there was a merge somewhere in between that range you will see all the commits as well so the outcome will be X+.

Good tip:

If you have to do it for more than a single branch and you might face conflicts when amending the content set up the git rerere and let git resolve those conflicts automatically for you.

11.6. Create branches

Branching allows you to build new features or test out ideas without putting your main project at risk. In git, branch is a sort of bookmark that references the last commit made in the branch. This makes branches very small and easy to work with.

How do I use branches?

Branches are pretty easy to work with and will save you a lot of headaches, especially when working with multiple people. To create a branch and begin working in it, run these commands:

git branch mybranch
# Creates a new branch called "mybranch"

git checkout mybranch
# Makes "mybranch" the active branch

Alternatively, you can use the shortcut:

git checkout -b mybranch
# Creates a new branch called "mybranch" and makes it the active branch

Create a branch tracking a remote branch, if it was created remotely:

git checkout -b serverfix origin/serverfix

Or push it, when ready:

git push <remote-name> <branch-name>

Where <remote-name> is typically origin, the name which git gives to the remote you cloned from. Note however that formally, the format is:

git push <remote-name> <local-branch-name>:<remote-branch-name>

To switch between branches, use git checkout:

git checkout master
# Makes "master" the active branch

git checkout mybranch
# Makes "mybranch" the active branch

Once you’re finished working on your branch and are ready to combine it back into the master branch, use merge:

git checkout master
# Makes "master" the active branch

git merge mybranch
# Merges the commits from "mybranch" into "master"

git branch -d mybranch
# Deletes the "mybranch" branch

Tip: When you switch between branches, the files that you work on (the “working copy”) are updated to reflect the changes in the new branch. If you have changes you have not committed, git will ensure you do not lose them. Git is also very careful during merges and pulls to ensure you don’t lose any changes. When in doubt, commit early and commit often.

11.7. Patches

See Create a git patch from the changes in the current working directory - Stack Overflow:

git format-patch master..my-branch

See How to apply a patch generated with git format-patch? - Stack Overflow

Note: You can first preview what your patch will do:

First the stats:

git apply --stat a_file.patch

Then a dry run to detect errors:

git apply --check a_file.patch
Finally, you can use git am to apply your patch as a commit: it allows you to sign off an applied patch.
This can be useful for later reference.
git am --signoff < a_file.patch

11.8. Github Forking

11.8.1. Step 3: Configure remotes

When a repository is cloned, it has a default remote called origin that points to your fork on GitHub, not the original repository it was forked from. To keep track of the original repository, you need to add another remote named upstream:

cd Spoon-Knife
# Changes the active directory in the prompt to the newly cloned "Spoon-Knife" directory

git remote add upstream https://github.com/octocat/Spoon-Knife.git
# Assigns the original repository to a remote called "upstream"

git fetch upstream
# Pulls in changes not present in your local repository, without modifying your files

To make it the default, use

git branch --set-upstream-to upstream/master

More Things You Can Do

You’ve successfully forked a repository, but get a load of these other cool things you can do: Push commits

Once you’ve made some commits to a forked repository and want to push it to your forked project, you do it the same way you would with a regular repository:

git push origin master
# Pushes commits to your remote repository stored on GitHub

Pull in upstream changes

If the original repository you forked your project from gets updated, you can add those updates to your fork by running the following code:

git fetch upstream
# Fetches any new changes from the original repository

git merge upstream/master
# Merges any changes fetched into your working files

What is the difference between fetch and pull?

There are two ways to get commits from a remote repository or branch: git fetch and git pull. While they might seem similar at first, there are distinct differences you should consider.

Pull:

git pull upstream master
# Pulls commits from 'upstream' and stores them in the local repository

When you use git pull, git tries to automatically do your work for you. It is context sensitive, so git will merge any pulled commits into the branch you are currently working in. One thing to keep in mind is that git pull automatically merges the commits without letting you review them first. If you don’t closely manage your branches you may run into frequent conflicts.

Fetch & Merge:

git fetch upstream
# Fetches any new commits from the original repository

git merge upstream/master
# Merges any fetched commits into your working files

When you git fetch, git retrieves any commits from the target remote that you do not have and stores them in your local repository. However, it does not merge them with your current branch. This is particularly useful if you need to keep your repository up to date but are working on something that might break if you update your files. To integrate the commits into your local branch, you use git merge. This combines the specified branches and prompts you if there are any conflicts.

11.9. Resolving merge conflicts with git and kdiff3

From http://jeroen.haegebaert.com/post/2008/08/26/Resolving-merge-conflicts-with-git-and-kdiff3

To fix the conflicts using kdiff3, first you need to tweak the kdiff3 configuration a bit: start kdiff3, and go to Settings, Configure KDiff3, Integration. Under ‘Command line options to ignore’, add ‘–’ separated by a ‘;’ if necessary. To resolve conflicts, you can now use:

git mergetool -t kdiff3

To permanently configure kdiff3 as the merge tool (so you don’t need to specify the ‘-t kdiff3’ anymore):

git config merge.tool kdiff3

11.10. Convert Mercurial Repository to git(1)

Source: GitHub - frej/fast-export: A mercurial to git converter using git-fast-import · GitHub

11.10.1. fast-export Installation

  • Clone repository in directory /srv/install/linux/fast-export.
  • Add script fast-export-inst.sh, if necessary.
  • Run fast-export-inst.sh '/usr/local/bin'

The icons used for ASCII art are courtesy of

## partition "Install hg-fast-export.sh" {                         #a2
# start                                                            #a2
## |:sec:| Setup  #ccccee                                          #a2 :;
# define installation directories                                  #a2 :;
# make sure repository installation directory exists               #a2 :;
_fe_inst_dir='/srv/install/linux/fast-export'; _fe_bin_dir='/usr/local/bin'; mkdir -p "${_fe_inst_dir}"
# if (enter repository installation directory?) then (yes)         #a2
( cd "${_fe_inst_dir}" || exit 1
# else                                                             #a2
# end                                                              #a2
# endif                                                            #a2
## |:sec:| Write Installer  #ccccee                                #a2 :;
  # if (fast-export-inst.sh does not exist\nor is empty?) then (yes) #a2
  test -s fast-export-inst.sh || {
    # Check required programs                                      #a2 :;
    ecode=0; for _prog in base64 gzip; do test -n "$( which "${_prog}" )" || { printf >&2 "# ||"":ERR:|| error: required program not found %s\n" "${_prog}"; ecode=1; }; done; test ${ecode} = 0 || exit 1;
    # if (base64(1) and gzip(1)\n are both available?) then (yes)  #a2
      # decode gzip/base64 encoded payload                         #a2 :
      # and install fast-export-inst.sh                            #a2 ;
      # note right                                                 #a2
      # The "thumbs up" indicates, that it is                      #a2
      # safe to execute the encoded script.                        #a2
      # end note                                                   #a2
    printf "%s\n" '                  H4sIAO/Hvm
                                       oA  A+09/Vfb
                                     SJK/        +9
                                       0f        UWuY
                                       2C          Zu
                                       2z          B7uX
                                       f2          JhOG
                                       kI            T3
                                       CP            AM
                                       XD            YP
                                     iGhL            LV
                                       sb            Wa
                                     1RSw            YG
                                     s3              /7
                                     VnVL            8nfG
                                     hi              S3
                                     c2              fP
                                   YOTu              6v
                                   rq                qu
                                 qq7j                bZ
                                 +Eu9
                                 4w
                               V11S
                             tsbE
                             DI            o9iLPRlA0eUqZuI2lFHMvEDFRb
                                     iHZV4bvEGY    VI  yo      lh  rwVUyEyv
                   Ulj7            2gC4                                  GM
                   BU              Re                                    t7cy
                 Ys0U              TI                                      tU
                 Uz                1gQE                                  /c96
               HXZW                  MA1L                              cY07
               d4                GUyJ4l3RnMvaxfHJ2cHx0ekVXPx6cMTeHLSvvobp2/
               GU              0v0G  mA          CG          IE        NtUPo1
               BB            51Vf                                            ro
               CG            VH                                              3l
               jvSq        /hGA                                              nmVI
                 Ex          R3SS                                          Ln4a
                 A3Ek          GQ2IW2En    aD      u2      7Pd5  4K  jH  kOgR
               iZ7w                Q5gkoXryBuKep8B0PkEKlvT926y9/feL5tmnkyt8
               PK                    ofoA                              hxxO
               0Y                  zj8c                                  guPx
             bsT7                  Cv                                      o8
               tn                  vk                                    Ge2/
               Qx                  mBAb                                  kQ
               /TC+                  AxnB9c  ATN9eV  jAQS    eSNcnv  gxpNZE
                 0N                  f1REV1X9rc  pzBwXdOAezK8M3  5W3qvA
                 TmPn              RRU+                              St/t
                   cqR1            av                                  dE
                     JKIq          /C1rqq        VN                wGPo9m
                                       9rjniFjgtnpBTX8wURosgC0h03dDiPPR
                                             +j
                                       jVC1QqGJJgPGHrQi
                                   yfFF4Biff/zLaFdzEkaStEbM
                                 uJEQoKQb3/BItOBOJmDzACLheCqO
                               vA7ZihcDmk            odFdmXjufe
                               IRpsSgIH                5Yx7AmIR4Q
                             ygRPTh3d                    E5vBOBiL
                             gPJ0nH                        92w49G
                           wRKAEcKV                        OL6gkHOo
                           SGBrwl                            Dk5TDu
                           CtRLyc                            HKEFws
                           P+CAYi                            UuQYP2
                           ckUnxV                            nFrEUU
                           ZVI9tR                            6l0V5P
                           UOfB6PRp                          qZnJZ8
                           JKCDgU                          8j7skQpe
                           khQpTv                            xsNI2B
                   EYloSb+FVASMTy8eDs/fH5  Gewe  fYKPu+327tHZpxbCxj2ZoHcNhM
                   Hk9UPfQ8QoU8QDskIXB3/Yb++9xxG7vx4cHpx9ItN8e3B2tH96Cm+P27
                   ALJ7vts4O988PdNpyct0+OT/drAKdCZJpFHAt06+rZQQU6Iuaer4zMn3
                   A60SsT34  Ee  H+  CK  IW  zh    DZAv  jg  Eg  vP  vjOUMc
                   3Jdo6i                                            Sh8e1U
                   hTU4cM                                            kkq6CQ
                   v7/14j                                            hs1us3
                   Nze1bp                                            DUZNSt
                   +waFqr                                            +qkQ+U
                   aWAAZe                                            QUteIw
                   3wsEbF                                            egrAIv
                   pEgv0A                                            +KXRFY
                   PacWo+                                            /SHBYh
                   xv+Kql                                            eEIkaF
                   L+IO1B                                            cvtBCJ
                   lYRoKC                                            Jt7SFC
                   1L6PHw                                            fcTwRa
                   S96B67                                            gv8o7S
                   3vHR24                                            N35+1d
                   Cu2lIn                                            KQES9W
                   KnqZXY                                            5V1bM6
                   NYJkIY97I06nEBKERRAvi5v3jYdiwXasE3wug+0AO4EavKo7YlAPErS3
                   nVfPtuHZM1SyF8QuFH9SlwGKzk6KUCkWwptsKD7R2KVHIs3DnObhcjQP
                   c5qHI5qHy4+8kdEXy/GijO7mPXHxALWWRrV5r1E/aCKkowwUfwe8LwDV
                   le  vu          oZ  iD        UZ        +G    63
                                             AlFg
                                         Da2JU3Iz5s9Y
                                     JCfasCzVarsFUpUECc
                                 IDri8ORhauTOmMQkbM47QlbgspAv
                             YMNpRUygQbZyqp        k55N319JnkeTCA
                       yKhQ3C4UKAnSI6yXk5            IWbnq0pDQLjtQjckCC
               G41K8emGOTrOAUc86qa5el                    4EnLFXxhDDHfSXLwugY6
       FiYL/DFIek2A4O/aKBsumbgM                                AJpL5sEuk5nchx6ayF4lkjJi
 ZktBYLOW8I0bByBadzl/c8zI                                            Gea18jXCtY2CIrm0A2zXBuOS
 MmM461+GMsp2rVZufI                                                        QJhgqIMe5imYAywVEm
 0ZuF7XciPZ                                                                        txxpLx3Cb2
 3XoQGj                                                                                SN33gm
 qAfFRx                                                                                AfYnIj
 UKjqH1                                                                                8dzVVG
 95vizL                                                                                Dlxl0R
 JoYV46rz                                                                              mWIal2
 qouMai                                                                              RNSro0Be
   S4mIfm                                                    QJi668                  x0GgqT
   3jFMkT                                                    3TH4/pbb                oTMyOL
   6rocYH                                                  uOMnGJfr                  nyCwcN
   h8OmEn                                                YTf8Pb86                    M9XTA9
   DtlKa69b                                            0wXjH0/j                      rKh6IJ
   QrhftRTL                                            odj63PlY                    jRlV7CLT
     6Qy13O                                          xO5yHqUa                      OjjpwD
     TjmdjX                                        asGcHrOc                        VuoZCP
     lc5rqb96                  f7byzr            pH38jinhPA                      ALoFT/vL
     FRd1qqCl                  sb/KLB/v          vq8nm12v                        q5Wv988X
       njqn7f                  Sh8I5vPG5X      O4/AX7w9                          ZDqzSx
       QjIiiSwb                    kYaz1Eqq+k/Gqvh/t1                            VQ1ddU
         t9DA19                      XSHDylMSj0gDEg                            /MQWLOcZ
         D5V8/J                        yqf4SJxrNFK/                            40rlLh
         4VGGZKW1                        5GoGlaeM                            q8Yh1wuc
           WniHdU                            Ow                              fCQKI+
           GK6GLn56                                                        usBcMjc3
             nM86hE                                                        4YiFXj
             g/Wi6vk5                                                    6/MKNdDd
               GAthyW                                                    FlFDWx
               j4vT73b5                                                9GmVRskV
                 1aXmBN5u                                            jLx4rVSK
                   IDWVRWBt                                        3VzWhFSk
                   jDF+y3RK                                      5QJZlBlh6E
                     SrYjCWwA                                    uObqFbaa
                       qr2qe57Gnq                            0GC3nDvpwF
                         TfDJWsdiO7                        b+Ib0lXOmp
                           tNCeYhFZgb                    9D6dpcH1kd
                             badGoY0W+aWn            soPAaNeOCEaJ
                               QeNpc9b/oqju/k  YyET5nEt9KAXV5
                                   3dlJP/F57A2E5SaBTbtA6IQi
                                       DL+7G96oyPWcmpvl
                                           vE6yQH0r
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' \
    | tr -d ' \r\n' | base64 -d | gzip -dc >fast-export-inst.sh;
      # if (fast-export-inst.sh does not exist\nor is empty?) then (yes) #a2
        # remove empty fast-export-inst.sh                         #a2 :;
        # end                                                      #a2
    test -s fast-export-inst.sh || { rm -f fast-export-inst.sh; exit 1; }
      # endif                                                      #a2
    # else                                                         #a2
      # report missing programs                                    #a2 :;
      # end                                                        #a2
    # endif                                                        #a2
    # make fast-export-inst.sh executable                          #a2 :;
    chmod 755 fast-export-inst.sh
  }
  # endif                                                          #a2
## |:sec:| Clone Repository and Install Scripts  #ccccee           #a2 :;
  # execute fast-export-inst.sh with bin directory argument        #a2 :;
  ./fast-export-inst.sh "${_fe_bin_dir}" )
# }
# stop                                                             #a2

The activity diagram for this install script wrapper, shows what is going on.

@startuml /' a2 '/
<style>
  /* Global style for all elements */
  element {
    XPadding: 10;
  }
</style>
   partition "Install hg-fast-export.sh" {
   start
partition "Setup" #ccccee {
   :define installation directories;
   :make sure repository installation directory exists;
   if (enter repository installation directory?) then (yes)
   else
   end
   endif
}
partition "Write Installer" #ccccee {
     if (fast-export-inst.sh does not exist\nor is empty?) then (yes)
       :Check required programs;
       if (base64(1) and gzip(1)\n are both available?) then (yes)
         :decode gzip/base64 encoded payload
         and install fast-export-inst.sh;
         note right
         The "thumbs up" indicates, that it is
         safe to execute the encoded script.
         end note
         if (fast-export-inst.sh does not exist\nor is empty?) then (yes)
           :remove empty fast-export-inst.sh;
           end
         endif
       else
         :report missing programs;
         end
       endif
       :make fast-export-inst.sh executable;
     endif
}
partition "Clone Repository and Install Scripts" #ccccee {
     :execute fast-export-inst.sh with bin directory argument;
   stop
}
@enduml

Unannotated version of the script:

_fe_inst_dir='/srv/install/linux/fast-export'; _fe_bin_dir='/usr/local/bin'; mkdir -p "${_fe_inst_dir}"
( cd "${_fe_inst_dir}" || exit 1
  test -s fast-export-inst.sh || {
    ecode=0; for _prog in base64 gzip; do test -n "$( which "${_prog}" )" || { printf >&2 "# ||"":ERR:|| error: required program not found %s\n" "${_prog}"; ecode=1; }; done; test ${ecode} = 0 || exit 1;
    printf "%s\n" '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' \
    | base64 -d | gzip -dc >fast-export-inst.sh;
    test -s fast-export-inst.sh || { rm -f fast-export-inst.sh; exit 1; }
    chmod 755 fast-export-inst.sh
  }
  ./fast-export-inst.sh "${_fe_bin_dir}" )

11.10.2. fast-export Usage

git init repo-git # or whatever
cd repo-git
hg-fast-export.sh -r <local-repo>
git checkout