diff --git a/app/models/concerns/with_git.rb b/app/models/concerns/with_git.rb
index d749a14032d2ae5f3e1f7f887fc0cd57e7c88240..6de6df853b214f1c7684227d9178f1082973b6df 100644
--- a/app/models/concerns/with_git.rb
+++ b/app/models/concerns/with_git.rb
@@ -21,7 +21,6 @@ module WithGit
   end
   handle_asynchronously :sync_with_git
 
-
   def git_path_static
     ''
   end
diff --git a/app/services/git/providers/github.rb b/app/services/git/providers/github.rb
index dc67bcbf2686cb36236df9aa00f3a8706b4cb718..714e65953da686c387013f937144dad1b2bfdea7 100644
--- a/app/services/git/providers/github.rb
+++ b/app/services/git/providers/github.rb
@@ -1,26 +1,31 @@
 class Git::Providers::Github
+  attr_reader :access_token, :repository
+
+  def initialize(access_token, repository)
+    @access_token = access_token
+    @repository = repository
+  end
 
   def add_to_batch( path: nil,
                     previous_path: nil,
                     data:)
-    @batch ||= []
     file = find_in_tree previous_path
     if file.nil? # New file
-      @batch << {
+      batch << {
         path: path,
         mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree
         type: 'blob',
         content: data
       }
-    elsif previous_path != path || file_sha(previous_path) != local_file_sha(data)
+    elsif previous_path != path || git_sha(previous_path) != sha(data)
       # Different path or content
-      @batch << {
+      batch << {
         path: previous_path,
         mode: file[:mode],
         type: file[:type],
         sha: nil
       }
-      @batch << {
+      batch << {
         path: path,
         mode: file[:mode],
         type: file[:type],
@@ -29,50 +34,32 @@ class Git::Providers::Github
     end
   end
 
-  def commit_batch(commit_message)
-    unless @batch.empty?
-      new_tree = client.create_tree repository, @batch, base_tree: tree[:sha]
-      commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha
-      client.update_branch repository, default_branch, commit[:sha]
-    end
-    @tree = nil
+  def push(commit_message)
+    return unless valid?
+    return if batch.empty?
+    new_tree = client.create_tree repository, batch, base_tree: tree[:sha]
+    commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha
+    client.update_branch repository, default_branch, commit[:sha]
     true
   end
 
-  def remove(path, commit_message)
-    client.delete_contents repository, path, commit_message, file_sha(path)
-    true
-  rescue
-    false
-  end
+  protected
 
-  def read_file_at(path)
-    data = client.content repository, path: path
-    Base64.decode64 data.content
-  rescue
-    ''
+  def valid?
+    repository.present? && access_token.present?
   end
 
-  protected
-
   def client
     @client ||= Octokit::Client.new access_token: access_token
   end
 
-  def file_sha(path)
-    begin
-      content = client.content repository, path: path
-      sha = content[:sha]
-    rescue
-      sha = nil
-    end
-    sha
+  def access_token
+    @access_token ||= website&.access_token
   end
 
-  def local_file_sha(data)
-    # Git SHA-1 is calculated from the String "blob <length>\x00<contents>"
-    # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
-    OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}"
+  # Path of the repo
+  def repository
+    @repository ||= website&.repository
   end
 
   def default_branch
@@ -87,14 +74,30 @@ class Git::Providers::Github
     @tree ||= client.tree repository, branch_sha, recursive: true
   end
 
+  def batch
+    @batch ||= []
+  end
+
+  def git_sha(path)
+    begin
+      content = client.content repository, path: path
+      sha = content[:sha]
+    rescue
+      sha = nil
+    end
+    sha
+  end
+
+  def sha(data)
+    # Git SHA-1 is calculated from the String "blob <length>\x00<contents>"
+    # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
+    OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}"
+  end
+
   def find_in_tree(path)
     tree[:tree].each do |file|
       return file if path == file[:path]
     end
     nil
   end
-
-  def tmp_directory
-    "tmp/github/#{repository}"
-  end
 end
diff --git a/app/services/git/repository.rb b/app/services/git/repository.rb
index 2c48cb8ff2a29505b17c7fced9c83b848805760d..7cd2916b4d92e233b89216dc67caf693fda2f063 100644
--- a/app/services/git/repository.rb
+++ b/app/services/git/repository.rb
@@ -11,125 +11,33 @@ class Git::Repository
   end
 
   def sync!
-    return unless valid?
     return if git_files.empty?
     sync_git_files
-    mark_as_synced if commit_batch
+    mark_as_synced if provider.push(commit_message)
   end
 
   protected
 
-  def client
-    @client ||= Octokit::Client.new access_token: access_token
-  end
-
-  def access_token
-    @access_token ||= website&.access_token
-  end
-
-  def repository
-    @repository ||= website&.repository
-  end
-
   def provider
-    @provider ||= Git::Providers::Github.new
+    @provider ||= Git::Providers::Github.new(website&.access_token, website&.repository)
   end
 
   def git_files
     @git_files ||= []
   end
 
-  def batch
-    @batch ||= []
-  end
-
-  def default_branch
-    @default_branch ||= client.repo(repository)[:default_branch]
-  end
-
-  def branch_sha
-    @branch_sha ||= client.branch(repository, default_branch)[:commit][:sha]
-  end
-
-  def tree
-    @tree ||= client.tree repository, branch_sha, recursive: true
-  end
-
-  def valid?
-    repository.present? && access_token.present?
-  end
-
   def sync_git_files
     git_files.each do |git_file|
       next if git_file.synced?
-      add_to_batch  path: git_file.path,
-                    previous_path: git_file.previous_path,
-                    data: git_file.to_s
-    end
-  end
-
-  def add_to_batch( path: nil,
-                    previous_path: nil,
-                    data:)
-    file = find_in_tree previous_path
-    if file.nil? # New file
-      batch << {
-        path: path,
-        mode: '100644', # https://docs.github.com/en/rest/reference/git#create-a-tree
-        type: 'blob',
-        content: data
-      }
-    elsif previous_path != path || git_sha(previous_path) != sha(data)
-      # Different path or content
-      batch << {
-        path: previous_path,
-        mode: file[:mode],
-        type: file[:type],
-        sha: nil
-      }
-      batch << {
-        path: path,
-        mode: file[:mode],
-        type: file[:type],
-        content: data
-      }
+      provider.add_to_batch path: git_file.path,
+                            previous_path: git_file.previous_path,
+                            data: git_file.to_s
     end
   end
 
-  def commit_batch
-    return if batch.empty?
-    new_tree = client.create_tree repository, batch, base_tree: tree[:sha]
-    commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha
-    client.update_branch repository, default_branch, commit[:sha]
-    true
-  end
-
   def mark_as_synced
     git_files.each do |git_file|
       git_file.update_columns previous_path: git_file.path, previous_sha: git_file.sha
     end
   end
-
-  def git_sha(path)
-    begin
-      content = client.content repository, path: path
-      sha = content[:sha]
-    rescue
-      sha = nil
-    end
-    sha
-  end
-
-  def sha(data)
-    # Git SHA-1 is calculated from the String "blob <length>\x00<contents>"
-    # Source: https://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html
-    OpenSSL::Digest::SHA1.hexdigest "blob #{data.bytesize}\x00#{data}"
-  end
-
-  def find_in_tree(path)
-    tree[:tree].each do |file|
-      return file if path == file[:path]
-    end
-    nil
-  end
 end
diff --git a/docs/websites/export.md b/docs/websites/export.md
index a4c71a4ac5b6f27e56be12bc5b7c4bcd3c49ac1d..bf9c2e88ad885f27f866847649dc9017d4e0bdab 100644
--- a/docs/websites/export.md
+++ b/docs/websites/export.md
@@ -67,6 +67,8 @@ def update
 end
 ```
 
+TODO gérer la suppression correctement
+
 ## Code
 
 ### Website::WithRepository