diff --git a/pom.xml b/pom.xml
index 6e7affb4a3fac1d91d17e27f9251b4fe68677525..03203dfe177917f47b23d2e8e653ba41608eddfb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,7 @@
         <codemirror.version>5.50.0</codemirror.version>
         <selenium.version>3.141.59</selenium.version>
         <assertj-core.version>3.17.1</assertj-core.version>
+        <jgit.version>5.10.0.202012080955-r</jgit.version>
 
         <app.versionDate>${maven.build.timestamp}</app.versionDate>
         <maven.build.timestamp.format>dd.MM.yy</maven.build.timestamp.format>
@@ -196,6 +197,11 @@
             <artifactId>codemirror</artifactId>
             <version>${codemirror.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.jgit</groupId>
+            <artifactId>org.eclipse.jgit</artifactId>
+            <version>${jgit.version}</version>
+        </dependency>
 
         <!-- selenium -->
         <dependency>
diff --git a/src/main/java/de/deadlocker8/budgetmaster/backup/GitHelper.java b/src/main/java/de/deadlocker8/budgetmaster/backup/GitHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..803f151c1181b6858fc3d0656a947bc57d8aefca
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/backup/GitHelper.java
@@ -0,0 +1,87 @@
+package de.deadlocker8.budgetmaster.backup;
+
+import org.eclipse.jgit.api.CommitCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PullResult;
+import org.eclipse.jgit.api.PushCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+
+public class GitHelper
+{
+	static class PullException extends Exception
+	{
+		public PullException(String message)
+		{
+			super(message);
+		}
+	}
+
+	private GitHelper()
+	{
+	}
+
+	public static void cloneRepository(String uri, CredentialsProvider credentialsProvider, Path targetFolder) throws GitAPIException
+	{
+		Git.cloneRepository()
+				.setURI(uri)
+				.setCredentialsProvider(credentialsProvider)
+				.setDirectory(targetFolder.toFile())
+				.call();
+	}
+
+	public static void createNewRepository(Path gitFolder) throws IOException
+	{
+		try(Repository newRepo = FileRepositoryBuilder.create(gitFolder.toFile()))
+		{
+			newRepo.create();
+		}
+	}
+
+	public static Repository openRepository(Path gitFolder) throws IOException
+	{
+		return new FileRepositoryBuilder()
+				.setGitDir(gitFolder.toFile())
+				.build();
+	}
+
+	public static void setRemote(Git git, String remote) throws URISyntaxException, GitAPIException
+	{
+		git.remoteAdd().setName("origin").setUri(new URIish(remote)).call();
+	}
+
+	public static void pullLatestChanges(Git git, CredentialsProvider credentialsProvider) throws GitAPIException, PullException
+	{
+		final PullResult result = git.pull()
+				.setCredentialsProvider(credentialsProvider)
+				.setRemote("origin")
+				.setRemoteBranchName("master")
+				.call();
+
+		if(!result.isSuccessful())
+		{
+			throw new PullException("Error while pulling changes.");
+		}
+	}
+
+	public static void commitChanges(Git git, String message) throws GitAPIException
+	{
+		final CommitCommand commit = git.commit();
+		commit.setMessage(message).call();
+	}
+
+	public static void push(Git git, CredentialsProvider credentialsProvider) throws GitAPIException
+	{
+		final PushCommand pushCommand = git.push();
+		pushCommand.setCredentialsProvider(credentialsProvider);
+		pushCommand.call();
+	}
+}
+
diff --git a/src/main/java/de/deadlocker8/budgetmaster/backup/LocalGitBackupTask.java b/src/main/java/de/deadlocker8/budgetmaster/backup/LocalGitBackupTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..76539b5e0e54b004fc69c4178c272e492d4014fc
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/backup/LocalGitBackupTask.java
@@ -0,0 +1,51 @@
+package de.deadlocker8.budgetmaster.backup;
+
+import de.deadlocker8.budgetmaster.Main;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Repository;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@Component
+public class LocalGitBackupTask implements Runnable
+{
+	private static final String DATE_PATTERN = "yyyy-MM-dd_HH-mm-ss";
+
+	private final Path gitFolder;
+
+	public LocalGitBackupTask()
+	{
+		final Path applicationSupportFolder = Main.getApplicationSupportFolder();
+		final Path backupFolder = applicationSupportFolder.resolve("backups");
+		this.gitFolder = backupFolder.resolve("git/.git");
+	}
+
+	@Override
+	public void run()
+	{
+		try
+		{
+			if(!Files.exists(gitFolder))
+			{
+				GitHelper.createNewRepository(gitFolder);
+			}
+
+			final Repository repository = GitHelper.openRepository(gitFolder);
+			final Git git = new Git(repository);
+
+			git.add().addFilepattern("*.mv.db").call();
+			GitHelper.commitChanges(git, DateTime.now().toString(DATE_PATTERN));
+		}
+		catch(IOException | GitAPIException e)
+		{
+			// TODO: error handling
+			e.printStackTrace();
+		}
+	}
+}
+
diff --git a/src/main/java/de/deadlocker8/budgetmaster/backup/RemoteGitBackupTask.java b/src/main/java/de/deadlocker8/budgetmaster/backup/RemoteGitBackupTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fce1e972919daddee1a8608618d351ef77c417f
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/backup/RemoteGitBackupTask.java
@@ -0,0 +1,61 @@
+package de.deadlocker8.budgetmaster.backup;
+
+import de.deadlocker8.budgetmaster.Main;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@Component
+public class RemoteGitBackupTask implements Runnable
+{
+	private static final String DATE_PATTERN = "yyyy-MM-dd_HH-mm-ss";
+
+	private final Path gitFolder;
+	private final UsernamePasswordCredentialsProvider credentialsProvider;
+	private final String remote;
+
+	public RemoteGitBackupTask()
+	{
+		final Path applicationSupportFolder = Main.getApplicationSupportFolder();
+		final Path backupFolder = applicationSupportFolder.resolve("backups");
+		this.gitFolder = backupFolder.resolve("git/.git");
+
+		this.credentialsProvider = new UsernamePasswordCredentialsProvider("", "");
+		this.remote = "https://thecodelabs.de/deadlocker8/bm_test.git";
+	}
+
+	@Override
+	public void run()
+	{
+		try
+		{
+			if(!Files.exists(gitFolder))
+			{
+				GitHelper.cloneRepository(this.remote, this.credentialsProvider, this.gitFolder.getParent());
+			}
+
+			final Repository repository = GitHelper.openRepository(gitFolder);
+			final Git git = new Git(repository);
+
+			GitHelper.setRemote(git, this.remote);
+			GitHelper.pullLatestChanges(git, credentialsProvider);
+
+			git.add().addFilepattern("*.mv.db").call();
+			GitHelper.commitChanges(git, DateTime.now().toString(DATE_PATTERN));
+			GitHelper.push(git, this.credentialsProvider);
+		}
+		catch(IOException | GitAPIException | URISyntaxException | GitHelper.PullException e)
+		{
+			e.printStackTrace();
+		}
+	}
+}
+