Version Control (Git)

Version Control (Git) #

Lecture source:

Get the detail content in your git commit (under the hood):

$ git cat-file -p <git_hash>

Get the git log in a graphed, linear way:

$ git log --all --graph --decorate [--oneline]

Resolve git merge conflict:

$ git mergetool
$ git add <your_files>
$ git merge --continue

Maintain the relationships betwen local and remote branches:

$ git branch --set-upstream-to=<remote name>/<remote branch>
# get the branch relations
$ git branch -vv

Clone only the lastest snapshot of a repository.

$ git clone --shallow <repo url>

An interactive interface for git add:

$ git add -p

Get information for a particular commit:

$ git show <commit hash>

Exercises #

  1. If you don’t have any past experience with Git, either try reading the first couple chapters of Pro Git or go through a tutorial like Learn Git Branching. As you’re working through it, relate Git commands to the data model.

    Skip it.

  2. Clone the repository for the class website.

    1. Explore the version history by visualizing it as a graph.

      $ git log --all --graph --decorate --oneline | head
      *   488e636 (HEAD -> master, origin/master, origin/HEAD) Merge pull request #187 from HtwoO/patch-1
      | * 90fe0de private key path is expected after -i of ssh client
      *   9837d16 Merge branch 'soulrrrrr/soulr'
      | * d8991dc Add <br> at the 'About the class' section. The 'Questions' title will move to the next line.
      *   b2c02c8 Merge pull request #178 from ChathurGudesa/master
    2. Who was the last person to modify (Hint: use git log with an argument).

      $ git log | head
      commit 8010724516adc968765e8efd14991f262f0d0423
      Author: Anish Athalye <[email protected]>
      Date:   Tue Jul 27 08:29:08 2021 -0400
          Separate build and links status
      commit 79d143ff650d59a2d69961b2c68d697096c0e8f4
      Author: Anish Athalye <[email protected]>
      Date:   Sat Dec 26 09:42:23 2020 -0500

      Obviously, is Anish.

    3. What was the commit message associated with the last modification to the collections: line of _config.yml? (Hint: use git blame and git show).

      $ git blame _config.yml | grep collections:
      a88b4eac (Anish Athalye 2020-01-17 15:26:30 -0500 18) collections:

      We have blame the last editor of collections: line is Anish Athalye, and the commit hash is a88b4eac. Now we can use git show with this commit hash to get the commit message.

      $ git show a88b4eac
      commit a88b4eac326483e29bdac5ee0a39b180948ae7fc
      Author: Anish Athalye <[email protected]>
      Date:   Fri Jan 17 15:26:30 2020 -0500
          Redo lectures as a collection
  3. One common mistake when learning Git is to commit large files that should not be managed by Git or adding sensitive information. Try adding a file to a repository, making some commits and then deleting that file from history (you may want to look at this).

    Init a new git workding directory first and make some commits.

    $ mkdir git-remove
    $ cd git-remove
    $ git init
    $ echo 'some sensitive data' > sensitive
    $ git add sensitive; git commit -m '1st commit'
    [master (root-commit) 41f6bfe] 1st commit
     1 file changed, 1 insertion(+)
     create mode 100644 sensitive
    $ echo 'another sensitive data' >> sensitive
    $ git add sensitive; git commit -m '2nd commit'
    [master 5d7bfa1] 2nd commit
     1 file changed, 1 insertion(+)
    $ echo 'the final sensitive data' >> sensitive
    $ git add sensitive; git commit -m '3rd commit'
    [master fe28712] 3rd commit
     1 file changed, 1 insertion(+)
    $ git log --all --graph --decorate --oneline
    * fe28712 (HEAD -> master) 3rd commit
    * 5d7bfa1 2nd commit
    * 41f6bfe 1st commit

    So the sensitive file should be removed, try to use the git filter-repo tool to achieve this.

    $ git filter-repo --invert-paths --force --path sensitive
    Parsed 3 commits
    New history written in 0.03 seconds; now repacking/cleaning...
    Repacking your repo and cleaning out old unneeded objects
    Enumerating objects: 1, done.
    Counting objects: 100% (1/1), done.
    Writing objects: 100% (1/1), done.
    Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
    Completely finished after 0.12 seconds.

    Why use --force in here?

    Our repo has inited maually so it is not a “fresh clone”, there are more than one line in .git/logs/HEAD, so the --force option is needed.

    Let’s check the sensitive file.

    $ ls -a
    .    ..   .git
    $ git log --all --graph --decorate --oneline

    So we can see the sensitive file has gone in the current working directory and the git log is empty now, the sensitive file not longer exists.

  4. Clone some repository from GitHub, and modify one of its existing files. What happens when you do git stash? What do you see when running git log --all --oneline? Run git stash pop to undo what you did with git stash. In what scenario might this be useful?

    $ git clone [email protected]:deb-sig/double-entry-generator.git some-test-repo
    Cloning into 'some-test-repo'...
    remote: Enumerating objects: 1159, done.
    remote: Counting objects: 100% (238/238), done.
    remote: Compressing objects: 100% (134/134), done.
    remote: Total 1159 (delta 144), reused 128 (delta 97), pack-reused 921
    Receiving objects: 100% (1159/1159), 1.87 MiB | 1.33 MiB/s, done.
    Resolving deltas: 100% (419/419), done.
    $ vim
    $ git diff
    diff --git a/ b/
    index cf6b33b..3acaca6 100644
    --- a/
    +++ b/
    @@ -1,3 +1,5 @@
    +This is a line for git stage test.
     # double-entry-generator

    Then we make the changes stashed.

    $ git stash
    Saved working directory and index state WIP on master: 6486dc0 fix two issues (#55)
    $ git log --all --oneline
    438ac40 WIP on master: 6486dc0 fix two issues (#55)
    191e798 index on master: 6486dc0 fix two issues (#55)
    6486dc0 fix two issues (#55)
    6a96eab feat: Update
    5350856 Initial commit

    The git stash makes temporary commits 191e798 and 438ac40 in this git log, and we can reveal some details for this commit by git show.

    $ git show 438ac40 | more
    commit 438ac4013e08d087d7858d1e773e5a9aa2038f04
    Merge: 6486dc0 191e798
    Author: Triple-Z <[email protected]>
    Date:   Tue Mar 15 22:50:18 2022 +0800
        WIP on master: 6486dc0 fix two issues (#55)
    diff --cc
    index cf6b33b,cf6b33b..3acaca6
    --- a/
    +++ b/
    @@@ -1,3 -1,3 +1,5 @@@
    ++This is a line for git stage test.
      # double-entry-generator

    Recover the changes by git stash pop.

    $ git stash pop
    On branch master
    Your branch is up to date with 'origin/master'.
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
    no changes added to commit (use "git add" and/or "git commit -a")
    Dropped refs/stash@{0} (438ac4013e08d087d7858d1e773e5a9aa2038f04)

    See the git log again, and the two commits at the top before are gone.

    $ git log --all --oneline | head -n 2
    6486dc0 fix two issues (#55)
    a3d710f fix(goreleaser): build with git version info (#53)
  5. Like many command line tools, Git provides a configuration file (or dotfile) called ~/.gitconfig. Create an alias in ~/.gitconfig so that when you run git graph, you get the output of git log --all --graph --decorate --oneline. Information about git aliases can be found here.

    Add the following lines to the ~/.gitconfig.

         graph = "log --all --graph --decorate --oneline"

    Then run the git graph, magic happens.

    $ git graph
    * 6486dc0 (HEAD -> master, origin/master, origin/HEAD) fix two issues (#55)
    * a3d710f (tag: v1.5.0) fix(goreleaser): build with git version info (#53)
    * 6a96eab feat: Update
    * 5350856 Initial commit
  6. You can define global ignore patterns in ~/.gitignore_global after running git config --global core.excludesfile ~/.gitignore_global. Do this, and set up your global gitignore file to ignore OS-specific or editor-specific temporary files, like .DS_Store.

    Set up the global gitignore to ignore .DS_Store.

    $ echo ".DS_Store" >> ~/.gitignore_global
    $ git config --global core.excludesfile ~/.gitignore_global

    Check if it works.

    $ touch .DS_Store
    $ ls -a
    .         ..        .DS_Store .git
    $ git status
    On branch master
    No commits yet
    nothing to commit (create/copy files and use "git add" to track)
  7. Fork the repository for the class website, find a typo or some other improvement you can make, and submit a pull request on GitHub (you may want to look at this).

    Skip it.