17

With the command adb pull /sdcard/ I can copy all the contents of the internal memory of my Android phone into my current local directory.

And adb pull /mnt/extSdCard/ does the same with the external SD card. But that command always copies everything, even files I already have stored locally.

Is there any way to copy only new and modified files? (files with a newer date)

4 Answers 4

9

adb-sync - small, yet powerfull python script that can do all your asked and more... https://github.com/google/adb-sync

3
  • Although the link maybe the answer for this user, it is best to fully explain the method and process to go through to make it work. android.stackexchange.com/help/how-to-answer
    – acejavelin
    Nov 13, 2017 at 17:49
  • 1
    Thanks for the mention. I had to make several changes to the source code to get it working for my use-case (invalid paths for Windows causing crash, Python version mismatch apparently, etc -- for details, see issues I commented in), but it ended up being the only way I was able to retrieve my files from a corrupted data partition. (the adb pull of the whole directory would crash on various files, and I didn't want to manually have to delete each one then restart the whole transfer -- with adb-sync [+my modifications] it would just fail that one file then continue)
    – Venryx
    Jul 22, 2019 at 1:02
  • 2
    Also note that project has been deprecated and one should rather use its successor: better-adb-sync
    – Izzy
    Jan 18 at 12:34
10

As described by ss-3-1415926535897932384626433 there is no flag, but you have to get a list of files first and then check if your local files match. I wrote a little script for it:

#!/bin/sh

rfolder=/sdcard/DCIM/Camera
lfolder=Camera

adb shell ls "$rfolder" > android.files

ls -1 "$lfolder" > local.files

rm -f update.files
touch update.files

while IFS=  read -r q; do
  # Remove non-printable characters (are not visible on console)
  l=$(echo ${q} | sed 's/[^[:print:]]//')
  # Populate files to update
  if ! grep -q "$l" local.files; then         
    echo "$l" >> update.files
  fi  
done < android.files

script_dir=$(pwd)
cd $lfolder

while IFS=  read -r q; do
  # Remove non-printable characters (are not visible on console)
  l=$(echo ${q} | sed 's/[^[:print:]]//')
  echo "Get file: $l"
  adb pull "$rfolder/$l"
done < "${script_dir}"/update.files

Adjust the remote folder rfolder and the local folder lfolder to locations of your own choice.

7
  • This looks pretty good. Does it also work recursively or just in a single directory and no subdirectories?
    – OMA
    Sep 16, 2015 at 22:56
  • This is non-recursive indeed, but feel free to improve. :-) Sep 19, 2015 at 19:08
  • Also note that I don't compare dates here yet, so if you have altered files they won't get updated. Sep 19, 2015 at 19:10
  • Meanwhile there's an (yet undocumented) option you can use: adb pull --sync -a (yes, you need -a as well to preserve timestamps). Works since version 27.0.1 (not before). In the other direction, adb push --sync (no -a needed funnily) is already available since at least 2015 (1.0.32 was the oldest version I tried). And yes: that works recursively and also updates older files (see my answer here).
    – Izzy
    Jan 18 at 8:40
  • 1
    @AnnevanRossum yes, answer linked. Or do you think I should duplicate the relevant part (not the entire answer)? Can be done of course.
    – Izzy
    Jan 18 at 12:09
4

adb pull doesn't seem to provide a flag to pull selected files.

As a workaround, you can do this: Use adb shell [Unix shell command] to copy selected files to a temporary location and then pull all files from that location.

Update:
You can use cp -u [source] [destination] unix shell command to copy only modified files on subsequent run. You can also use -r flag to use it on subdirectories recursive, if its required.

4
  • Thanks for your answer. Copying all files to another location to then maybe update just one changed file is pretty slow. Too bad that adb doesn't provice in way to copy only newer files.
    – OMA
    Feb 28, 2013 at 4:50
  • @OMA You can use the shell to get a list of new files, and then use adb pull on that list. Feb 28, 2013 at 16:35
  • @MatthewRead Any hints on how to do that? Thanks!
    – OMA
    Feb 28, 2013 at 17:29
  • @OMA I am unable to understand your problem with this. Use both commands in one line or create alias (also add a command to purge temp location after operation). If there was a flag of adb pull for that, it'd work the same way.
    – iOS
    Mar 2, 2013 at 10:42
2

Though not fully documented, starting with 27.0.1 aka platform tools r27 (not before) the following can be used:

adb push --sync local/ device/
# adb pull --sync -a device/. local/

(note the trailing dot on adb pull; without that you'd end up with local/device/*, see here; also the -a is needed only here to keep the timestamps of the files intact)

Not directly related to adb push: file permissions are not kept, which is probably due to the file system used. Files pushed to the internal SD card will always be set to 0660 and on the external card to 0771, which I could not even change using adb shell chmod on the device itself (though I received no error either on trying).

If you need more options as you might know them from rsync (e.g. --delete or --exclude), you can also take a look at the Python script better-adb-sync.

Update: running a few tests it seems --sync is simply ignored with adb pull even if no error is thrown: newer files on target have been overwritten! Not sure if implementation is planned, but with r27 being released in 2018 I'd not place a bet on that. With push it works as advertized, though.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .