1. 28 5月, 2015 1 次提交
  2. 13 3月, 2015 24 次提交
    • N
      git-status.txt: advertisement for untracked cache · aeb6f8b3
      Nguyễn Thái Ngọc Duy 提交于
      When a good user sees the "too long, consider -uno" advice when
      running `git status`, they should check out the man page to find out
      more. This change suggests they try untracked cache before -uno.
      Helped-by: Nbrian m. carlson <sandals@crustytoothpaste.net>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      aeb6f8b3
    • N
      untracked cache: guard and disable on system changes · 1e8fef60
      Nguyễn Thái Ngọc Duy 提交于
      If the user enables untracked cache, then
      
       - move worktree to an unsupported filesystem
       - or simply upgrade OS
       - or move the whole (portable) disk from one machine to another
       - or access a shared fs from another machine
      
      there's no guarantee that untracked cache can still function properly.
      Record the worktree location and OS footprint in the cache. If it
      changes, err on the safe side and disable the cache. The user can
      'update-index --untracked-cache' again to make sure all conditions are
      met.
      
      This adds a new requirement that setup_git_directory* must be called
      before read_cache() because we need worktree location by then, or the
      cache is dropped.
      
      This change does not cover all bases, you can fool it if you try
      hard. The point is to stop accidents.
      Helped-by: NEric Sunshine <sunshine@sunshineco.com>
      Helped-by: Nbrian m. carlson <sandals@crustytoothpaste.net>
      Helped-by: NTorsten Bögershausen <tboegi@web.de>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      1e8fef60
    • N
      7b6aff06
    • N
      a3ddcefd
    • N
    • N
      update-index: manually enable or disable untracked cache · 9e597241
      Nguyễn Thái Ngọc Duy 提交于
      Overall time saving on "git status" is about 40% in the best case
      scenario, removing ..collect_untracked() as the most time consuming
      function. read and refresh index operations are now at the top (which
      should drop when index-helper and/or watchman support is added). More
      numbers and analysis below.
      
      webkit.git
      ==========
      
      169k files. 6k dirs. Lots of test data (i.e. not touched most of the
      time)
      
      Base status
      -----------
      
      Index version 4 in split index mode and cache-tree populated. No
      untracked cache. It shows how time is consumed by "git status". The
      same settings are used for other repos below.
      
      18:28:10.199679 builtin/commit.c:1394   performance: 0.000000451 s: cmd_status:setup
      18:28:10.474847 read-cache.c:1407       performance: 0.274873831 s: read_index
      18:28:10.475295 read-cache.c:1407       performance: 0.000000656 s: read_index
      18:28:10.728443 preload-index.c:131     performance: 0.253147487 s: read_index_preload
      18:28:10.741422 read-cache.c:1254       performance: 0.012868340 s: refresh_index
      18:28:10.752300 wt-status.c:623         performance: 0.010421357 s: wt_status_collect_changes_worktree
      18:28:10.762069 wt-status.c:629         performance: 0.009644748 s: wt_status_collect_changes_index
      18:28:11.601019 wt-status.c:632         performance: 0.838859547 s: wt_status_collect_untracked
      18:28:11.605939 builtin/commit.c:1421   performance: 0.004835004 s: cmd_status:update_index
      18:28:11.606580 trace.c:415             performance: 1.407878388 s: git command: 'git' 'status'
      
      Populating status
      -----------------
      
      This is after enabling untracked cache and the cache is still empty.
      We see a slight increase in .._collect_untracked() and update_index
      (because new cache has to be written to $GIT_DIR/index).
      
      18:28:18.915213 builtin/commit.c:1394   performance: 0.000000326 s: cmd_status:setup
      18:28:19.197364 read-cache.c:1407       performance: 0.281901416 s: read_index
      18:28:19.197754 read-cache.c:1407       performance: 0.000000546 s: read_index
      18:28:19.451355 preload-index.c:131     performance: 0.253599607 s: read_index_preload
      18:28:19.464400 read-cache.c:1254       performance: 0.012935336 s: refresh_index
      18:28:19.475115 wt-status.c:623         performance: 0.010236920 s: wt_status_collect_changes_worktree
      18:28:19.486022 wt-status.c:629         performance: 0.010801685 s: wt_status_collect_changes_index
      18:28:20.362660 wt-status.c:632         performance: 0.876551366 s: wt_status_collect_untracked
      18:28:20.396199 builtin/commit.c:1421   performance: 0.033447969 s: cmd_status:update_index
      18:28:20.396939 trace.c:415             performance: 1.482695902 s: git command: 'git' 'status'
      
      Populated status
      ----------------
      
      After the cache is populated, wt_status_collect_untracked() drops 82%
      from 0.838s to 0.144s. Overall time drops 45%. Top offenders are now
      read_index() and read_index_preload().
      
      18:28:20.408605 builtin/commit.c:1394   performance: 0.000000457 s: cmd_status:setup
      18:28:20.692864 read-cache.c:1407       performance: 0.283980458 s: read_index
      18:28:20.693273 read-cache.c:1407       performance: 0.000000661 s: read_index
      18:28:20.958814 preload-index.c:131     performance: 0.265540254 s: read_index_preload
      18:28:20.972375 read-cache.c:1254       performance: 0.013437429 s: refresh_index
      18:28:20.983959 wt-status.c:623         performance: 0.011146646 s: wt_status_collect_changes_worktree
      18:28:20.993948 wt-status.c:629         performance: 0.009879094 s: wt_status_collect_changes_index
      18:28:21.138125 wt-status.c:632         performance: 0.144084737 s: wt_status_collect_untracked
      18:28:21.173678 builtin/commit.c:1421   performance: 0.035463949 s: cmd_status:update_index
      18:28:21.174251 trace.c:415             performance: 0.766707355 s: git command: 'git' 'status'
      
      gentoo-x86.git
      ==============
      
      This repository is a strange one with a balanced, wide and shallow
      worktree (about 100k files and 23k dirs) and no .gitignore in
      worktree. .._collect_untracked() time drops 88%, total time drops 56%.
      
      Base status
      -----------
      18:20:40.828642 builtin/commit.c:1394   performance: 0.000000496 s: cmd_status:setup
      18:20:41.027233 read-cache.c:1407       performance: 0.198130532 s: read_index
      18:20:41.027670 read-cache.c:1407       performance: 0.000000581 s: read_index
      18:20:41.171716 preload-index.c:131     performance: 0.144045594 s: read_index_preload
      18:20:41.179171 read-cache.c:1254       performance: 0.007320424 s: refresh_index
      18:20:41.185785 wt-status.c:623         performance: 0.006144638 s: wt_status_collect_changes_worktree
      18:20:41.192701 wt-status.c:629         performance: 0.006780184 s: wt_status_collect_changes_index
      18:20:41.991723 wt-status.c:632         performance: 0.798927029 s: wt_status_collect_untracked
      18:20:41.994664 builtin/commit.c:1421   performance: 0.002852772 s: cmd_status:update_index
      18:20:41.995458 trace.c:415             performance: 1.168427502 s: git command: 'git' 'status'
      Populating status
      -----------------
      18:20:48.968848 builtin/commit.c:1394   performance: 0.000000380 s: cmd_status:setup
      18:20:49.172918 read-cache.c:1407       performance: 0.203734214 s: read_index
      18:20:49.173341 read-cache.c:1407       performance: 0.000000562 s: read_index
      18:20:49.320013 preload-index.c:131     performance: 0.146671391 s: read_index_preload
      18:20:49.328039 read-cache.c:1254       performance: 0.007921957 s: refresh_index
      18:20:49.334680 wt-status.c:623         performance: 0.006172020 s: wt_status_collect_changes_worktree
      18:20:49.342526 wt-status.c:629         performance: 0.007731746 s: wt_status_collect_changes_index
      18:20:50.257510 wt-status.c:632         performance: 0.914864222 s: wt_status_collect_untracked
      18:20:50.338371 builtin/commit.c:1421   performance: 0.080776477 s: cmd_status:update_index
      18:20:50.338900 trace.c:415             performance: 1.371462446 s: git command: 'git' 'status'
      Populated status
      ----------------
      18:20:50.351160 builtin/commit.c:1394   performance: 0.000000571 s: cmd_status:setup
      18:20:50.577358 read-cache.c:1407       performance: 0.225917338 s: read_index
      18:20:50.577794 read-cache.c:1407       performance: 0.000000617 s: read_index
      18:20:50.734140 preload-index.c:131     performance: 0.156345564 s: read_index_preload
      18:20:50.745717 read-cache.c:1254       performance: 0.011463075 s: refresh_index
      18:20:50.755176 wt-status.c:623         performance: 0.008877929 s: wt_status_collect_changes_worktree
      18:20:50.763768 wt-status.c:629         performance: 0.008471633 s: wt_status_collect_changes_index
      18:20:50.854885 wt-status.c:632         performance: 0.090988721 s: wt_status_collect_untracked
      18:20:50.857765 builtin/commit.c:1421   performance: 0.002789097 s: cmd_status:update_index
      18:20:50.858411 trace.c:415             performance: 0.508647673 s: git command: 'git' 'status'
      
      linux-2.6
      =========
      
      Reference repo. Not too big. .._collect_status() drops 84%. Total time
      drops 42%.
      
      Base status
      -----------
      18:34:09.870122 builtin/commit.c:1394   performance: 0.000000385 s: cmd_status:setup
      18:34:09.943218 read-cache.c:1407       performance: 0.072871177 s: read_index
      18:34:09.943614 read-cache.c:1407       performance: 0.000000491 s: read_index
      18:34:10.004364 preload-index.c:131     performance: 0.060748102 s: read_index_preload
      18:34:10.008190 read-cache.c:1254       performance: 0.003714285 s: refresh_index
      18:34:10.012087 wt-status.c:623         performance: 0.002775446 s: wt_status_collect_changes_worktree
      18:34:10.016054 wt-status.c:629         performance: 0.003862140 s: wt_status_collect_changes_index
      18:34:10.214747 wt-status.c:632         performance: 0.198604837 s: wt_status_collect_untracked
      18:34:10.216102 builtin/commit.c:1421   performance: 0.001244166 s: cmd_status:update_index
      18:34:10.216817 trace.c:415             performance: 0.347670735 s: git command: 'git' 'status'
      Populating status
      -----------------
      18:34:16.595102 builtin/commit.c:1394   performance: 0.000000456 s: cmd_status:setup
      18:34:16.666600 read-cache.c:1407       performance: 0.070992413 s: read_index
      18:34:16.667012 read-cache.c:1407       performance: 0.000000606 s: read_index
      18:34:16.729375 preload-index.c:131     performance: 0.062362492 s: read_index_preload
      18:34:16.732565 read-cache.c:1254       performance: 0.003075517 s: refresh_index
      18:34:16.736148 wt-status.c:623         performance: 0.002422201 s: wt_status_collect_changes_worktree
      18:34:16.739990 wt-status.c:629         performance: 0.003746618 s: wt_status_collect_changes_index
      18:34:16.948505 wt-status.c:632         performance: 0.208426710 s: wt_status_collect_untracked
      18:34:16.961744 builtin/commit.c:1421   performance: 0.013151887 s: cmd_status:update_index
      18:34:16.962233 trace.c:415             performance: 0.368537535 s: git command: 'git' 'status'
      Populated status
      ----------------
      18:34:16.970026 builtin/commit.c:1394   performance: 0.000000631 s: cmd_status:setup
      18:34:17.046235 read-cache.c:1407       performance: 0.075904673 s: read_index
      18:34:17.046644 read-cache.c:1407       performance: 0.000000681 s: read_index
      18:34:17.113564 preload-index.c:131     performance: 0.066920253 s: read_index_preload
      18:34:17.117281 read-cache.c:1254       performance: 0.003604055 s: refresh_index
      18:34:17.121115 wt-status.c:623         performance: 0.002508345 s: wt_status_collect_changes_worktree
      18:34:17.125089 wt-status.c:629         performance: 0.003871636 s: wt_status_collect_changes_index
      18:34:17.156089 wt-status.c:632         performance: 0.030895703 s: wt_status_collect_untracked
      18:34:17.169861 builtin/commit.c:1421   performance: 0.013686404 s: cmd_status:update_index
      18:34:17.170391 trace.c:415             performance: 0.201474531 s: git command: 'git' 'status'
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      9e597241
    • N
      status: enable untracked cache · 226c051a
      Nguyễn Thái Ngọc Duy 提交于
      update_index_if_able() is moved down so that the updated untracked
      cache could be written out.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      226c051a
    • N
      untracked-cache: temporarily disable with $GIT_DISABLE_UNTRACKED_CACHE · 76e6b090
      Nguyễn Thái Ngọc Duy 提交于
      This can be used to double check if results with untracked cache are
      correctly, compared to vanilla version. Untracked cache remains in
      index, but not used.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      76e6b090
    • N
    • N
      untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATS · c9ccb5d3
      Nguyễn Thái Ngọc Duy 提交于
      This could be used to verify correct behavior in tests
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      c9ccb5d3
    • N
      untracked cache: avoid racy timestamps · ed4efab1
      Nguyễn Thái Ngọc Duy 提交于
      When a directory is updated within the same second that its timestamp
      is last saved, we cannot realize the directory has been updated by
      checking timestamps. Assume the worst (something is update). See
      29e4d363 (Racy GIT - 2005-12-20) for more information.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      ed4efab1
    • N
    • N
      untracked cache: invalidate at index addition or removal · e931371a
      Nguyễn Thái Ngọc Duy 提交于
      Ideally we should implement untracked_cache_remove_from_index() and
      untracked_cache_add_to_index() so that they update untracked cache
      right away instead of invalidating it and wait for read_directory()
      next time to deal with it. But that may need some more work in
      unpack-trees.c. So stay simple as the first step.
      
      The new call in add_index_entry_with_check() may look strange because
      new calls usually stay close to cache_tree_invalidate_path(). We do it
      a bit later than c_t_i_p() in this function because if it's about
      replacing the entry with the same name, we don't care (but cache-tree
      does).
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      e931371a
    • N
    • N
    • N
    • N
      untracked cache: don't open non-existent .gitignore · 27b099ae
      Nguyễn Thái Ngọc Duy 提交于
      This cuts down a signficant number of open(.gitignore) because most
      directories usually don't have .gitignore files.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      27b099ae
    • N
      untracked cache: mark what dirs should be recursed/saved · 26cb0182
      Nguyễn Thái Ngọc Duy 提交于
      If we redo this thing in a functional style, we would have one struct
      untracked_dir as input tree and another as output. The input is used
      for verification. The output is a brand new tree, reflecting current
      worktree.
      
      But that means recreate a lot of dir nodes even if a lot could be
      shared between input and output trees in good cases. So we go with the
      messy but efficient way, combining both input and output trees into
      one. We need a way to know which node in this combined tree belongs to
      the output. This is the purpose of this "recurse" flag.
      
      "valid" bit can't be used for this because it's about data of the node
      except the subdirs. When we invalidate a directory, we want to keep
      cached data of the subdirs intact even though we don't really know
      what subdir still exists (yet). Then we check worktree to see what
      actual subdir remains on disk. Those will have 'recurse' bit set
      again. If cached data for those are still valid, we may be able to
      avoid computing exclude files for them. Those subdirs that are deleted
      will have 'recurse' remained clear and their 'valid' bits do not
      matter.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      26cb0182
    • N
      untracked cache: record/validate dir mtime and reuse cached output · 91a2288b
      Nguyễn Thái Ngọc Duy 提交于
      The main readdir loop in read_directory_recursive() is replaced with a
      new one that checks if cached results of a directory is still valid.
      
      If a file is added or removed from the index, the containing directory
      is invalidated (but not its subdirs). If directory's mtime is changed,
      the same happens. If a .gitignore is updated, the containing directory
      and all subdirs are invalidated recursively. If dir_struct#flags or
      other conditions change, the cache is ignored.
      
      If a directory is invalidated, we opendir/readdir/closedir and run the
      exclude machinery on that directory listing as usual. If untracked
      cache is also enabled, we'll update the cache along the way. If a
      directory is validated, we simply pull the untracked listing out from
      the cache. The cache also records the list of direct subdirs that we
      have to recurse in. Fully excluded directories are seen as "untracked
      files".
      
      In the best case when no dirs are invalidated, read_directory()
      becomes a series of
      
        stat(dir), open(.gitignore), fstat(), read(), close() and optionally
        hash_sha1_file()
      
      For comparison, standard read_directory() is a sequence of
      
        opendir(), readdir(), open(.gitignore), fstat(), read(), close(), the
        expensive last_exclude_matching() and closedir().
      
      We already try not to open(.gitignore) if we know it does not exist,
      so open/fstat/read/close sequence does not apply to every
      directory. The sequence could be reduced further, as noted in
      prep_exclude() in another patch. So in theory, the entire best-case
      read_directory sequence could be reduced to a series of stat() and
      nothing else.
      
      This is not a silver bullet approach. When you compile a C file, for
      example, the old .o file is removed and a new one with the same name
      created, effectively invalidating the containing directory's cache
      (but not its subdirectories). If your build process touches every
      directory, this cache adds extra overhead for nothing, so it's a good
      idea to separate generated files from tracked files.. Editors may use
      the same strategy for saving files. And of course you're out of luck
      running your repo on an unsupported filesystem and/or operating system.
      Helped-by: NEric Sunshine <sunshine@sunshineco.com>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      91a2288b
    • N
      untracked cache: make a wrapper around {open,read,close}dir() · cf7c6148
      Nguyễn Thái Ngọc Duy 提交于
      This allows us to feed different info to read_directory_recursive()
      based on untracked cache in the next patch.
      Helped-by: NRamsay Jones <ramsay@ramsay1.demon.co.uk>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      cf7c6148
    • N
      untracked cache: invalidate dirs recursively if .gitignore changes · 5ebf79ad
      Nguyễn Thái Ngọc Duy 提交于
      It's easy to see that if an existing .gitignore changes, its SHA-1
      would be different and invalidate_gitignore() is called.
      
      If .gitignore is removed, add_excludes() will treat it like an empty
      .gitignore, which again should invalidate the cached directory data.
      
      if .gitignore is added, lookup_untracked() already fills initial
      .gitignore SHA-1 as "empty file", so again invalidate_gitignore() is
      called.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      5ebf79ad
    • N
      untracked cache: initial untracked cache validation · ccad261f
      Nguyễn Thái Ngọc Duy 提交于
      Make sure the starting conditions and all global exclude files are
      good to go. If not, either disable untracked cache completely, or wipe
      out the cache and start fresh.
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      ccad261f
    • N
      untracked cache: record .gitignore information and dir hierarchy · 0dcb8d7f
      Nguyễn Thái Ngọc Duy 提交于
      The idea is if we can capture all input and (non-rescursive) output of
      read_directory_recursive(), and can verify later that all the input is
      the same, then the second r_d_r() should produce the same output as in
      the first run.
      
      The requirement for this to work is stat info of a directory MUST
      change if an entry is added to or removed from that directory (and
      should not change often otherwise). If your OS and filesystem do not
      meet this requirement, untracked cache is not for you. Most file
      systems on *nix should be fine. On Windows, NTFS is fine while FAT may
      not be [1] even though FAT on Linux seems to be fine.
      
      The list of input of r_d_r() is in the big comment block in dir.h. In
      short, the output of a directory (not counting subdirs) mainly depends
      on stat info of the directory in question, all .gitignore leading to
      it and the check_only flag when r_d_r() is called recursively. This
      patch records all this info (and the output) as r_d_r() runs.
      
      Two hash_sha1_file() are required for $GIT_DIR/info/exclude and
      core.excludesfile unless their stat data matches. hash_sha1_file() is
      only needed when .gitignore files in the worktree are modified,
      otherwise their SHA-1 in index is used (see the previous patch).
      
      We could store stat data for .gitignore files so we don't have to
      rehash them if their content is different from index, but I think
      .gitignore files are rarely modified, so not worth extra cache data
      (and hashing penalty read-cache.c:verify_hdr(), as we will be storing
      this as an index extension).
      
      The implication is, if you change .gitignore, you better add it to the
      index soon or you lose all the benefit of untracked cache because a
      modified .gitignore invalidates all subdirs recursively. This is
      especially bad for .gitignore at root.
      
      This cached output is about untracked files only, not ignored files
      because the number of tracked files is usually small, so small cache
      overhead, while the number of ignored files could go really high
      (e.g. *.o files mixing with source code).
      
      [1] "Description of NTFS date and time stamps for files and folders"
          http://support.microsoft.com/kb/299648Helped-by: NTorsten Bögershausen <tboegi@web.de>
      Helped-by: NDavid Turner <dturner@twopensource.com>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      0dcb8d7f
    • N
      dir.c: optionally compute sha-1 of a .gitignore file · 55fe6f51
      Nguyễn Thái Ngọc Duy 提交于
      This is not used anywhere yet. But the goal is to compare quickly if a
      .gitignore file has changed when we have the SHA-1 of both old (cached
      somewhere) and new (from index or a tree) versions.
      Helped-by: NJunio C Hamano <gitster@pobox.com>
      Helped-by: NTorsten Bögershausen <tboegi@web.de>
      Signed-off-by: NNguyễn Thái Ngọc Duy <pclouds@gmail.com>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      55fe6f51
  3. 11 3月, 2015 3 次提交
    • J
      Post 2.3 cycle (batch #9) · 7a9409cb
      Junio C Hamano 提交于
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      7a9409cb
    • J
      Merge branch 'mh/expire-updateref-fixes' · 82b7e651
      Junio C Hamano 提交于
      Various issues around "reflog expire", e.g. using --updateref when
      expiring a reflog for a symbolic reference, have been corrected
      and/or made saner.
      
      * mh/expire-updateref-fixes:
        reflog_expire(): never update a reference to null_sha1
        reflog_expire(): ignore --updateref for symbolic references
        reflog: improve and update documentation
        struct ref_lock: delete the force_write member
        lock_ref_sha1_basic(): do not set force_write for missing references
        write_ref_sha1(): move write elision test to callers
        write_ref_sha1(): remove check for lock == NULL
      82b7e651
    • J
      Merge branch 'jk/diffcore-rename-duplicate' · 2d659f7d
      Junio C Hamano 提交于
      A corrupt input to "git diff -M" can cause us to segfault.
      
      * jk/diffcore-rename-duplicate:
        diffcore-rename: avoid processing duplicate destinations
        diffcore-rename: split locate_rename_dst into two functions
      2d659f7d
  4. 07 3月, 2015 12 次提交