In Git, every line of the file .gitignore is a regular expression that describes files that should be ignored. However, one can also add lines that state which files not to ignore.

Example:

The following example shows a configuration that ignores everything in a particular directory (./tmp) but explicitly states that PDF files in ./tmp should not be ignored:

# Ignore everything in ./tmp ...
/tmp/*

# ... but do not ignore PDF files in ./tmp
!/tmp/*.pdf

 

Allgemeine Konfiguration

Generischer Befehl:

git config

Git speichert Einstellungen auf drei Ebenen:

  • –file (default): für das aktuelle Repository
  • –global: für den aktuellen Benutzer
  • –system: für das gesamte System

Die wichtigsten Funktionalitäten sind:

  • Einstellung abfragen:
    git config --global
    
  • Einstellung setzen (–replace-all, da sonst ein weiterer und kein neuer Wert für gespeichert wird):
    git config --global --replace-all 
    
  • Einstellungen abfragen:
    git config --global --list
    

     

Nützliche Optionen sind dabei (Git macht auch Vorschläge, wenn man TAB betätigt):

  • user.name: Benutzername für Commit-Nachrichten
  • user.e-mail: Mailadresse für Commit-Nachrichten
  • core.editor: Editor für Nachrichten oder längere Texte (bspw. nano oder [Vim])
  • alias: Setzt mal beispielsweise alias.co auf checkout, dann kann man einen Checkout von nun an auch neben dem ursprünglichen langen git checkout mit dem Kurzbefehl git co durchführen.

Repository initialisieren

  • Repository im aktuellen Verzeichnis neu erstellen:
    git init
    
  • Ein existierendes Repository ins aktuelle Verzeichnis klonen (–shared: auch andere Benutzer des Systems können darauf zugreifen):
    git clone --shared  .
    
  • Diese Seite wird von nun an den Namen origin tragen.

Hinzufügen, Entfernen und Anzeigen von Dateien

  • Datei file.txt zum Repository hinzufügen
    git add file.txt
    
  • Dies funktioniert auch für Verzeichnisse.
  • Git fügt keine leeren Verzeichnisse hinzu!
  • Der Befehl git add file.txt hat noch zwei weitere Funktionen:
  • # Stage: Falls die Datei file.txt in den nächsten Commit aufgenommen werden soll.
  • # Resolved: Falls die Datei file.txt einen Konflikt hatte und jetzt als gelöst (resolved) markiert werden soll.
  • Datei file.txt aus dem Repository löschen:
  • Datei file.txt auch vom Dateisystem löschen:
    git rm file.txt
    
  • Datei file.txt nicht vom Dateisystem löschen:
    git rm --cached file.txt
    
  • Alle aktuelle versionierten Dateien anzeigen:
    git ls-files
  • Aktuellen Status anzeigen (Was wird committed? Was wurde verändert?):
    git status
    
  • Mit der Option -v bekommt man die Differenz zum Original angezeigt.

Änderungen rückgängig machen

Das Äquivalent eines Reverts (svn revert file.txt) bei Subversion lautet:

git reset HEAD test.txt     # only necessary if file has been deleted
git checkout -- test.txt

Entferntes Repository

  • Änderungen holen (Äquivalent eines Updatesvn update– bei Subversion):
  • Falls man nur eine entfernte Seite hat, dann ist der Aufruf einfach:
    git pull
    
  • Ansonsten muss man die entfernte Seite mit Namen (origin) (und ggfs. sogar Branch – master – nennen):
    git pull origin master
    
  • Änderungen schreiben (Äquivalent eines Commitsvn commit– bei Subversion)
  • Falls man nur eine entfernte Seite hat, dann ist der Aufruf einfach:
    git push
    
  • Ansonsten muss man die entfernte Seite mit Namen (origin) (und ggfs. sogar Branch – master – nennen):
    git push origin master
    

Informationen über entfernte Repositories

  • Ausführliche Informationen über remote comp5lx mittels git remote show :
  • Option -n verhindert, dass der Remote angesprochen wird, ansonsten funktioniert die Anfrage nur, wenn man gerade online ist.
    $ git remote show comp5lx -n
    * remote comp5lx
     Fetch URL: ssh://comp5lx/var/git/repo.git
     Push URL: ssh://comp5lx/var/git/repo.git
     HEAD branch: (not queried)
     Remote branch: (status not queried)
     master
     Local ref configured for 'git push' (status not queried):
     (matching) pushes to (matching)

Nachträglich entfernte Repositories tracken

Es kann unter Umständen passieren, dass der aktuelle lokale Branch einen entfernten Branch origin/b_remote nicht trackt und man dies nachholen möchte. In diesem Fall kann man mit der Option -u beim Pushen den Upstream Branch aktualisieren:

git push -u origin b_remote

Siehe auch: hier

Gespeicherte Zwischenstände (Tags)

Git bietet anders als Subversion eine integrierte Verwaltung von Tags:

  • Alle Tags auflisten:
    git tag
    
  • Tag erstellen (-f erzwingt Überschreiben):
    git tag -a "Version_1.0"
    
  • Tag löschen:
    git tag -d "Version_1.0"
    

Zweige (Branches)

  • Alle Branches auflisten:
    git branch
    
  • Branch neuer_branch erstellen
    git checkout -b "neuer_branch"
    
  • Branch löschen:
    git checkout master          # Branch verlassen
    git branch -d "neuer_branch"
    
  • Änderungen aus dem Branch neuer_branch in den Branch master übernehmen:
    git checkout master      # Branch wechseln
    git merge "neuer_branch" # Änderungen integrieren
    

 

GitHub mit einem anderen Identity File verwenden

Normalerweise nimmt der SSH-Befehl an, dass der öffentliche Schlüssel unter ~/.ssh/id_rsa.pub zu finden ist.
Möchte man nun einen anderen Schlüssel verwenden, dann sind die folgenden Schritte nötig:

    • Füge eine Hostdefinition in die Datei ~/.ssh/config ein:
      Host github
        Port 22
        Hostname github.com
        User git
        IdentityFile ~/.ssh/github_key
      
    • Hinzufügen/Klonen der remote site:
git remote add origin ssh://github/RomeoKilo/repository

Diverses

  • Passwort temporär speichern (default: 900 Sekunden):
    git config credential.helper cache
    git config credential.helper 'cache --timeout=300'
    
  • Fast Forward deaktivieren für Merges in den Master:
    git config --global branch.master.mergeoptions  "--no-ff" 
    
  • Lokale Kopien von entfernten Branches löschen, falls diese nicht mehr existieren:
    git fetch -p origin
    
  • Übersicht über den Zustand des Repositories:
    gitk --all
    
  • Grafisch mit Git arbeiten:
    git gui
    
  • Branches löschen, dir zwar als remote/… gekennzeichnet sind, aber in Wirklichkeit nicht mehr auf dem jeweiligen Remote-Server existieren:
    git remote prune origin
    
  • Hübsche Bash-Prompt:
    export PS1='\[\033[01;32m\]\u\[\033[01;34m\] \w\[\033[31m\]$(__git_ps1 " (%s)")\[\033[01;34m\]$\[\033[00m\] '
    

git.config (Beispiel)

Nutzerspezifische Einstellungen werden in der Datei ‘~/.gitconfig’ gespeichert:

[user]
        name = Rüdiger Kluge
        email = ruediger.kluge@conelek.com
[core]
#        autocrlf = true
[alias]
        l = log --graph --pretty=oneline --abbrev-commit --decorate
        lt = log --topo-order --graph --pretty=oneline --abbrev-commit --decorate
[color]
        # turn on color
        diff = auto
        status = auto
        branch = auto
        interactive = auto
        ui = auto
[color "branch"]
        # good looking colors i copy/pasted from somewhere
        current = green bold
        local = green
        remote = red bold
[color "diff"]
        # good looking colors i copy/pasted from somewhere
        meta = yellow bold
        frag = magenta bold
        old = red bold
        new = green bold
[color "status"]
        # good looking colors i copy/pasted from somewhere
        added = green bold
        changed = yellow bold
        untracked = red
[push]
        # 'git push' should only do the current branch, not all
        default = current
[branch]
        # always setup 'git pull' to rebase instead of merge
        autosetuprebase = always
[alias]
        st = status
        ci = commit
        br = branch
        co = checkout
        df = diff
[branch "master"]
    mergeoptions = --no-ff

Links

 

The suggested way of adding all untracked files to the index in Git is to use the interactive add command:

$ git add -i
           staged     unstaged path

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> a
  1: testfile1.txt
Add untracked>> *
added one path
*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> quit
Bye.

This can be fully automated as follows:

echo -e "a\n*\nq\n"|git add -i

The commands entered via standard input (a,*,q) will not be printed. For convenience, we can also define an alias in ~/.gitconfig:

[alias]
    add-untracked = !"echo \"a\\n*\\nq\\n\" | git add -i"

References

  • [1] Mat’s and EAGER_STUDENT’s answer on StackOverflow

 

git-svn keeps empty directories, which may become a problem (e.g.) when renaming directories. This behavior manifests in messages such as “W: -empty_dir abc/dir” during dcommit and, how it can be altered, I describe in this article.

Configuration for removing empty directories during git svn dcommit

To avoid keeping empty directories around, use the –rmdir flag during git svn dcommit:

git svn dcommit --rmdir

To make this behavior permanent, we can use git config (Can be verified by taking a look at the [svn] section in ~/.gitconfig):

git config --global svn.rmdir true

Now, when performing svn dcommit, you should see that empty directories get deleted (see the lines starting with D+).

Removing legacy empty directories

For the time being, we only fixed the future behavior of git svn, but there are still empty directories left in the Subversion repository. To clean these up, we need an Subversion working copy of the repository. Go to the SVN working copy and determine the empty directories:

find . -wholename './.svn' -prune -o -type d -empty -print > empty_dirs.txt

This call will exclude the .svn directory (-prune flag) and include the “lowest” empty directories in the directory tree. Therefore, we need to iterate the deletion procedure several times until no more empty “leaf directories” remain. Next, investigate empty_dirs.txt and see whether it contains directories that you want to keep – edit empty_dirs.txt if necessary:

grep -f empty_dirs.txt empty_dirs.txt

Now comes the time to schedule the directories for deletion (if there remain empty directories to be deleted):

grep -f empty_dirs.txt empty_dirs.txt | xargs svn delete

Now, rerun the find command to find directories that are now eligible for deletion and repeat the xargs svn delete. At the end, review you changes with svn status and commit them with

svn commit

Finally, the same steps have to be performed in the git svn working copy after a git svn rebase.

References

  • [1] Peter Boling describes a similar solution

A local Git repository holds a copy of any remote branch that has ever been fetched. Even though remote branches (origin/…) may already have been deleted, the local copies of these branches are kept indefinitely if we do not delete them by hand.

The following command removes missing remote branches of remote origin:

git remote prune origin

For testing purposes we may add the option –dry-run.

References

  • [1] git remote man page

The following is a suggested setup of the Git configuration file (_~/.gitconfig):

[user]
    email = my mail address
    name = Roland Kluge
[core]
    editor = vim
    excludesfile = ~/.gitexcludes
[branch "master"]
    mergeoptions = --no-ff
[alias]
        l = log --graph --pretty=oneline --abbrev-commit --decorate
        lt = log --topo-order --graph --pretty=oneline --abbrev-commit --decorate
[color]
        # turn on color
        diff = auto
        status = auto
        branch = auto
        interactive = auto
        ui = auto
[color "branch"]
        current = green bold
        local = green
        remote = red bold
[color "diff"]
        meta = yellow bold
        frag = magenta bold
        old = red bold
        new = green bold
[color "status"]
        added = green bold
        changed = yellow bold
        untracked = red
[push]
        # 'git push' should only do the current branch, not all
        default = current
[branch]
        # always setup 'git pull' to rebase instead of merge
        autosetuprebase = always
[alias]
        st = status
        ci = commit
        br = branch
        co = checkout
        df = diff

From time to time you want to take a look at a file in the past of your Git repository’s history. The following instructions will tell you how to see (and save) a file at a certain commit in the Git history.

Finding the right commit

Depending on the use case there are different ways of finding the commit you want to take a look at. In any case, after this step you will have a commit id or a branch-relative index which can be used to refer to the desired commit.

Referring to recent commit

If you know that the file was in the desired state in the previous, last but one, etc. commit, you can use the “~ operator”:

  • previous commit: HEAD~1
  • last but one commit: HEAD~2
  • head of certain branch: branch123
  • commit before head of branch: branch123~1
  • etc.

Listing files under version control

The command git ls-tree shows you the files which were under version control at a certain point in time:

git ls-tree --name-only HEAD~1  # non-recursive
git ls-tree -r --name-only HEAD~1  # recursive

Deleted files

Suppose you have deleted the file and want to know in which particular commit you deleted it, then the following command will be helpful, which prints out all log entries which contain a delete instruction (you may search as normal with the “/” operator):

git log --diff-filter=D --summary

Git bisection search

If you don’t know the exact version (commit) of the file, but given the file in some state, you can decide whether the appropriate version has been created rather before or after a given one. In this case the bisection search of Git may help: You tell Git a range of commits which surely “enclose” the desired version of your file. The most recent commit is called the bad state and the oldest commit is called the good state, because the bisection search is meant for finding a commit which introduced a bug which has not been there at some point in the past. In our setting, we are not looking for a bug but for a particular version of a file.

git bisect startgit bisect bad # uses the HEAD
git bisect good <commit id some time in the past>
# e.g., Bisecting: 113 revisions left to test after this (roughly 7 steps)

The bisection search will place you at the “center” between good and bad (you can also visualize the situation with the command git bisect visualize). And now you can examine the file in question whether you think the change is in the future or the past of this commit. In the former case (“future”), our we need to tell Git that the current state is good (“bug” in the future):

git bisect good

Likewise, in the latter case we find that the “bug” is in the past and tell Git so:

git bisect bad

Iterate, until you are done. Then, or if you would like to abort the bisection, type:

git bisect revert

Restoring the file

Now that you have the commit of your choice, use the git show command to display or store the file.

git show HEAD~3:README.txt # show the file contents
git show HEAD~3:README.txt > /tmp/README.txt # store the file contents

shows README.txt file in the 3rd last commit of the current branch.

git show issue123~1:doc/html/index.html # show
git show issue123~1:doc/html/index.html > /tmp/index.html # store

shows index.html in the subdirectory doc/html in the state it was one commit before the HEAD of the branch issue123.

You can delete a remote branch topic_branch located in the repository origin using the git push command:

git push origin :topic_branch

The semantics is that you push an empty reference (before the colon) to the remote branch and therewith delete it.

Links

It may happen that you create a local branch and forget to make it track a remote branch. We can make up for this by using the –set-upstream-to option of the git branch command. Say we are currently on branch issue123 and we want to make this branch track origin‘s issue123 branch.

For Git versions >=1.8

git fetch # may be necessary in order to get origin/issue123
git branch --set-upstream-to=origin/issue123 issue123

For Git versions <= 1.7

Mind the switched order of arguments. This command will also work in later Git versions:

git branch --set-upstream issue123 origin/issue123

 Links